Array of pointers implementation in C - c

Hii ,
I have been trying to write a program... We have a structure which has a rank field and the name field.The pointer to this structure is stored in an array of fixed size. I have implemented it as follows and i have certain problems...
The code i have written is :
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct
{
int rank;
char *name;
}node;
int insert(node **a , char name[] , int *rank)
{
if(*rank >= 5)
{
printf("\n Overflow ");
return 0;
}
(*rank)++;
node *new = (node *)malloc(sizeof(node));
new->name = name;
new->rank = *rank;
a[*rank] = new;
return 0;
}
int delete(node **a , int *rank)
{
int i = *rank;
if(*rank<0)
{
printf("\n No elements");
return 0;
}
printf("\n Deleting %d , %s ",((a[*rank]))->rank,((a[*rank]))->name);
printf("\n Reordering the elements ");
while(i<5)
{
a[i] = a[i+1];
}
return 0;
}
int display(node **a , int rank)
{
while(rank>0 && (a[rank])>0)
{
printf(" rank = %d name = %s \n",((a[rank])->rank),((a[rank])->name));
rank--;
}
return 0;
}
int main()
{
node *a[5] = {NULL};
char ch = 'y';
int choice,rank = -1;
char name[10];
while(ch!='n' || ch!= 'N')
{
printf("\n Enter 1 to insert , 2 to delete , 3 to display and 4 to exit \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("\n Enter name to insert");
gets(name);
insert(a,name,&rank);
break;
case 2:
printf("\n Enter rank to delete ");
scanf("%d",&rank);
delete(a,&rank);
break;
case 3:
display(a,rank);
break;
case 4:
exit(0);
default:
printf("\n Invalid choice...please enter again ");
break;
}
ch = getchar();
}
return 0;
}
First thing is the system automatically takes the choice except for the first time...(i couldn't find the fault there...) and i am a bit confused about this pointer stuff...Please see if its alright...Any corrections are welcome and please give me some explanation as to why it is wrong and how we shd do it...
Thank You

First of all, all your functions always return 0 -- even for an error condition. Life would be so much easier, if you passed rank in as an int, and returned it's new value.
rank = insert(a, name, rank);
/* : */
/* : */
int insert(node **a , char name[] , int rank)
{
if(rank >= 5)
{
printf("\n Overflow ");
return 0;
}
rank++;
node *new = (node *)malloc(sizeof(node));
new->name = name;
new->rank = rank;
a[rank] = new;
return rank;
}
It's been many years since I last used scanf, but as I recall, you must account for every character in the stream, meaning,"Don't forget the Enter".
scanf("%d\n",&choice);
Also with gets(name);, if you type more tha 9 characters, you are quite screwed, as it will overwrite the stack of your program.
UPDATE:
Also, you have two ways to exit this program, except one will never work. You could choose option "4" which will call exit(0). Alternately, at the end of each command, you wait for a character before stepping over. It appears you want to be able to enter "N" ther and exit, except that won't work:
while(ch!='n' || ch!= 'N')
for that to evaluate to false, ch must be both "n" & "N" at the same time. You really want
while(ch!='n' && ch!= 'N')
UPDATE2:
I just noticed the biggest problem in you code. name everywhere in your code only ever points to the single array defined in main(). Everytime you enter a new name, it overwrites that array, and since every node points to that one array, the name changes everywhere. You need to make a copy.
in insert():
node *new = (node *)malloc(sizeof(node));
new->name = strdup(name); // use malloc internally.
Then in delete() you'll have to free that memory (speaking of which, you need to free node there too...)
printf("\n Deleting %d , %s ",((a[*rank]))->rank,((a[*rank]))->name);
free(a[*rank]->name);
free(a[*rank]);
printf("\n Reordering the elements ");
Remember, Whenever you call malloc, you will eventually have to call free.

I'm confused as to the use of the "rank" variable. Main uses it as an index to the last node in the array, and the nodes use it as a ranking. Adding nodes increases it, but deleting nodes doesn't decrease it.
In the very least, I'd suggest separate the index variable from the ranking variable to make the logic easier to follow.
Personally, I'd write a structure to encapsulate the array with its own index tracking and add/delete functions. That way Main is free to read in user options and manipulate rank of new nodes without worrying about data structure details.

while(ch!='n' || ch!= 'N')
{
printf("\n Enter 1 to insert , 2 to delete , 3 to display and 4 to exit \n");
scanf("%d",&choice); getchar();
.
.
.
//ch = getchar();
}
Using getchar() along with scanf() causes this problem. Since '\n' after reading a character into 'ch' goes as an input to scanf. One way to resolve your problem is read that '\n' with an extra getchar() before it is read by gets().
Also you should modify while loop in delete.

Related

(C programming) bus error on my linked list

I'm learning to use linkedlist, I feel I already understand the concept but when coding why do I always get an error (bus error)....this code can run, but only until "SCANF the NAME" after that an error appears.
typedef struct Student{
char name[20];
char idNum[10];
int saving;
struct Student *next;
}Student;
Student *head = NULL;
void insert_student(){
char *name,*idNum;
int saving;
Student *current;
Student *new_student;
new_student = (Student*)malloc(sizeof(Student));
// apakah ada memoory kosong?
if(new_student==NULL){
printf("==== YOUR MEMMORY IS FULL! ====\n");
exit(0);
}
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
printf("How many your money : Rp");scanf("%d",&saving);
strcpy(new_student->name,name);
strcpy(new_student->idNum,idNum);
new_student->saving = saving;
new_student->next = NULL;
if(head==NULL){
head = new_student;
}
else{
current = head;
while (current->next != NULL)
{
current = current->next;
}
current->next = new_student;
}
}
void print_students(){
Student *current;
if(head==NULL){
printf("==== THERE IS NO STUDENT YET!\n");
exit(0);
}
current = head;
while (current!= NULL)
{
printf("Name : %s",current->name);
printf("id : %s",current->idNum);
printf("Saving : Rp%d",current->saving);
current = current->next;
}
}
int main(){
insert_student();
print_students();
return 0;
}
I'm hoping to create nodes for the dynamic linked-list Student and then display them
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
You have to give named and idNum meaningful values before you pass their values to scanf. Instead, you are just passing uninitialized garbage value to scanf, which won't work. You must pass to scanf pointers to the place you want the strings you're reading in to be stored.
For starters it is a bad idea to make the functions to depend on the global variable head. In this case you will not be able to use more than one list in the program.
Within the function insert_student you declared uninitialized pointers name and idNum:
char *name,*idNum;
So using them in the calls of scanf
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
invokes undefined behavior.
You need to declare character arrays instead of pointers
char name[20], idNum[10];
Also the format specifications are incorrect.
You should write
printf("Enter your name : "); scanf( " %19[^\n]", name );
printf("Enter your Id : "); scanf( " %9[^\n]", idNum );
Pay attention to the leading space in the format strings It allows to skip white space characters.
Otherwise after this call of scanf
printf("How many your money : Rp");scanf("%d",&saving);
the input buffer will contain the new line character '\n'. So when you will call the function insert_student a second time the first call of scanf (if the format specification does not contain the leading space)
printf("Enter your name : "); scanf( "%19[^\n]", name );
will read an empty string.
Also it is not a flexible approach when the whole program exits if a new node was not allocated.
if(new_student==NULL){
printf("==== YOUR MEMMORY IS FULL! ====\n");
exit(0);
}
It will be better to return to the caller an integer that will report whether the function was executed successfully. For example
int insert_student( void )
{
//...
Student *new_student;
new_student = (Student*)malloc(sizeof(Student));
int success = new_student != NULL;
if ( success )
{
printf("Enter your name : ");scanf("%[^\n]s",name);
printf("Enter your Id : ");scanf("%[^\n]s",idNum);
printf("How many your money : Rp");scanf("%d",&saving);
//...
}
return success;
}

How can i display stack C

How could I display stack when I insert x in to programs.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int Data;
struct Node* next;
} * top;
void popStack()
{
struct Node *temp, *var = top;
if (var == top)
{
top = top->next;
free(var);
}
else
printf("\nStack Empty");
}
void push(int value)
{
struct Node* temp;
temp = (struct Node*)malloc(sizeof(struct Node));
temp->Data = value;
if (top == NULL)
{
top = temp;
top->next = NULL;
}
else
{
temp->next = top;
top = temp;
}
}
void display()
{
struct Node* var = top;
if (var != NULL)
{
printf("\nElements are as:\n");
while (var != NULL)
{
printf("\t%d\n", var->Data);
var = var->next;
}
printf("\n");
}
else
printf("\nStack is Empty");
}
int main(int argc, char* argv[])
{
printf(" Wellcome to Basic Stacking. \n");
top = NULL;
while (1)
{
when i insert "x" I want program to display stack and exit but it does not work after I insert x in this programs it will be infinite loop and don't display the stack and don't exit what should i do????.
char x ;
int value;
if (value != x)
{
printf("please enter Your Name:");
scanf("%d", &value);
push(value);
fflush(stdin);
display();
}
else
{
// popStack();
display();
break;
}
}
getch();
}
Some programmer dude already spotted, but I want to be a little more explicit:
char x;
int value;
if (value != x)
Both x and value are uninitialized, they could hold any value. If you compare them, it is very unlikely that they will match, but they could by accident even at the first time you enter the loop (leading to immediate exit). It is very unlikely, too, that variable x holds the value of 'x' – in the end, it is undefined behaviour anyway to read uninitialized variables...
Next problem is: You simply use scanf("%d"). This will fail trying to read input, if you type in an 'x' character, because that one cannot be scanned as a number. So you would have to read a string first and then parse it. Both errors fixed together, your code might look like this:
char buffer[128];
while(1)
{
if(!fgets(buffer, sizeof(buffer), stdin))
break; // some error occured
if(*buffer == 'x') // you can compare directly, you don't need a char x = 'x'; ...
break;
int value;
char c;
if(sscanf(buffer, "%d %c", &value, &c) == 1)
{
// ...
}
else
{
puts("invalid input");
fflush(stdout);
}
}
Scanning for an additional character after the number (important: the space character before is needed to skip white space, i. e. the terminating newline character got from fgets) together with checking the return value of sscanf detects invalid input such as 'abc' or '1xyz'.
Additionally, have a look at your popStack function:
struct Node* var = top;
if (var == top)
This will always be true, even it top is NULL: then var is NULL, too, and NULL is equal to itself, of course...
You should rather do it this way:
if (top)
{
struct Node* var = top;
top = top->next;
free(var);
}
Good practice is always checking the return value of malloc. Although it shouldn't ever fail in such a small program like yours, you won't forget it later when writing larger programs if you get used to right from the start...
Together with some code simplification (admitted, cosmetics only, but the if is not necessary...):
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
if(temp)
{
temp->Data = value;
temp->next = top;
top = temp;
}
else
{
// appropriate error handling
}
One last recommendation: Your two functions form a functional pair, so prefer reflecting this in their names, too: either "push" and "pop" or "pushStack" and "popStack".
I found out your problem! This was kinda of an headache since the program was always going for an infinite loop!
But the problem is you are reading characters with scanf("%d",&value). This scanf doesn't remove the input from the buffer, so every other scanf you do after will have the same input ('x'), which your scanf can't read.
To fix this change these lines:
printf("please enter Your Name:");
scanf("%d", &value);
to
printf("please enter Your Name:");
if(scanf("%d", &value)==0)value=x;
So if scanf isn't successful then you assume the user wants to exit.
This is also a duplicate question, lease refer to this question, for more details.
Your comparison of value against x always invokes undefined behaviour. The scope of value is the loop body. Effectively you get a "new" value each time you go round the loop.
Your scanf is looking for a number. If you expect the loop to terminate when you press the x key on your keyboard, it is not going to work. The scanf will actually fail because x is not a valid match sequence for %d. On the other hand, if you type in 120 which is the ASCII code for x you might get lucky and see the loop terminate because the undefined behaviour might include reusing the same location for value on each iteration of the loop.
To fix this, define read value before you do the comparison to see if it is x. Also, you'll have to read it using, for example fgets(), then check it to see if it x and then, if it isn't maybe use strtol() or sscanf() to convert it to a number.

Basic Linked List operations in C

I am creating a program to perform basic linked list operations. Right now i have wrote the code only for inserting the node at the front. I ran my program to see its working or not but the program is terminating after accepting the input for the node, then it prints the message after switch. It doesn't even pause for accepting my input for continuing the operations (just before end of main())
here is the code :
#include <stdio.h>
#include <stdlib.h>
struct linkedlist
{
int num;
struct linkedlist *next;
};
struct linkedlist *head = NULL;
void display();
void insertBeginning()
{
struct linkedlist *obj;
int no;
obj = (struct linkedlist *)malloc(sizeof(struct linkedlist));
if(obj == NULL)
{
printf("\n Overflow ");
}
else
{
printf("\n Enter the number = ");
scanf("%d", &no);
obj->num = no;
if(head == NULL)
{
head = obj;
obj->next = NULL;
}
else
{
obj->next = head;
head = obj;
}
}
}
void display ()
{
struct linkedlist *head2 = head;
while(head2 != NULL)
{
printf("%d ->",head2->num);
head2=head->next;
}
printf("NULL \n");
}
int main()
{
int choice;
char wish;
printf("\n 1. Insert at beginning");
printf("\n 2. Insert at end");
printf("\n 3. Insert in between");
printf("\n 4. Delete from front");
printf("\n 5. Delete from end");
printf("\n 6. Delete from in between");
printf("\n 7. Reverse");
printf("\n 8. Sort ascending");
printf("\n 9. Sort descending");
printf("\n 10.Swap alternate elements");
printf("\n 11.Display\n\n");
do
{
printf("\n Enter the option = ");
scanf("%d", &choice);
switch(choice)
{
case 1:
insertBeginning();
break;
case 2:
// insertEnd();
break;
case 3:
// insertInbetween();
break;
case 4:
// deleteFront();
break;
case 5:
// deleteEnd();
break;
case 6:
// deleteInbetween();
break;
case 7:
// Reverse();
break;
case 8:
// sortAsc();
break;
case 9:
// sortDesc();
break;
case 10:
// swap();
break;
case 11:
display();
break;
default:
printf("\n Wrong choice ");
}
printf("\n Do you wish to continue (y/n) = ");
scanf ("%c",&wish);
}while(wish == 'y' || wish =='Y');
return 0;
}
In your case, you have to change
scanf ("%c",&wish);
to
scanf (" %c",&wish);
because, if you don't include the leading white-space before the format specifier, it will consider the remaining \n (newline) which got generated and stored into the input buffer by pressing ENTER key after the first input. So, the second scanf() won't wait for the user input.
when calling scanf()
1) with a '%d' format specifier, the trailing newline, from where the user entered the number, will not be consume.
2) with a '%c' format specifier, leading white space, like a newline, will cause the scanf() to fail, leaving the parameter (wish) unchanged.
3) in the posted code, when the 'wish' does not contain a valid 'Y' or 'y' then the program exits.
I agree with the other poster, that adding a choice '0' for exiting would be a much better way than the separate call to scanf()
there is a new line after giving the input 'choice' which scan by the variable 'wish'. So we need to remove that newline ('\n').
So if you want the user to continue just use a getchar() before take the input wish. Its easy and simple.
printf("\n Do you wish to continue (y/n) = ");
getchar();
scanf ("%c",&wish);

Premature exit of an input loop

In my program to sort a linked list using selection and bubble sort, getdata() is used to get data from the user.
getdata()
{
int val;
char c;
struct node *new;
new = NULL;
do {
printf("Enter a value:\n");
scanf("%d",&val);
append(&new,val);
printf("Any more nodes(y/n):\n");
c=getchar();
} while(c =='y' || c =='Y');
start = new;
}
But when I run my program the output is
Enter a value: 3
Any More Nodes (Y/N): Linked List Before Sorting: 3
Linked List After Selection Sorting: 3
Enter a value: 2
Any More Nodes (Y/N): Linked List Before Sorting: 2
Linked List After Bubble Sorting: 2
I'm not able to type "y/n" in it. Can someone tell me what is wrong?
The scanf("%d", &val); leaves the newline in the input buffer, so the getchar() reads the newline, which is neither y nor Y, so the loop terminates.
You should probably use:
if (scanf(" %c", &c) != 1)
break;
You should also test the result of scanf("%d", &val) to ensure you get a value.
Your function should also be declared with an explicit return type. For the code shown, that should be void. Note that your code is unnecessarily tied to the global variable start. If you changed the function to struct node *getdata(void) { …; return new; } then you could use it more generally.
instead of c=getchar(); try cin.get();

Linked list trouble

Does anyone know what might be the problem with the following code? When I run it, I get the following output:
Insert a value in the list: 1
Do you want to continue? y/N:
1 ->
The fact is that the do-while loop executes until the scanf("%c", &ch) statement, and then it jumps out (so I cannot provide any input for the ch variable). I tried debugging with GDB and I got some weird messages:
GI___libc_malloc (bytes=16) at malloc.c:malloc.c: No such file or directory.
Also, it says that the compiler couldn't find the vscanf.c file. Does anyone have an explanation for this strange behavior? Thanks! (The intention was to print the values of a singly linked list in reverse order.)
#include <stdio.h>
#include <stdlib.h>
struct node{
int info;
struct node* next;
};
struct node* head = 0;
void add_node(int value){
struct node* current = malloc(sizeof(struct node));
current->info = value;
current->next = head;
head = current;
}
void print_node(struct node* head){
while(head){
printf(" %d -> ", head->info);
head = head->next;
}
printf("\n");
}
int main(void){
int val;
char ch;
do {
printf("Insert a value in the list: ");
scanf("%d", &val);
add_node(val);
printf("Do you want to continue? y/N: ");
scanf("%c", &ch);
} while(ch == 'y' || ch == 'Y');
printf("\n");
print_node(head);
return 0;
}
If you want the input to be separated by a new line (which it appears that you do) then change the format of how you are reading in your character. Change following:
scanf( "%c", &ch );
... to this:
scanf( "\n%c", &ch ); // << Note, \n to pickup newline before reading the value.
You can check for proper input in an if-else block, and execute your code accordingly.
For example, here is something I would do if I needed to check whether the user wants to continue or not:
char chTemp; //Declare a test variable to check for newline
printf("Do you want to continue? y/N: ");
if (scanf("%c%c",&ch,&chTemp) != 2 || chTemp != '\n')
{
printf("Error in input (Integer input provided)");
}
else
{
//Do stuff.
}
Not only will it solve your problem, but it will also check for careless integer inputs.
The problem you are encountering is because the once you type a value for val and then press enter , then \n still remains in the input buffer . Hence , the next scanf assumes that \n which is still in the input buffer is its input , and consumes it and then loop exits .
Other Solutions :-
1) scanf("%d%*c",&val);
This would assign the first input character to val and then anything after that would be eaten up . Hence , the \n would not go into the next scanf
2) scanf("%[^\n]%*c",&val);
This would assign the anything to the val except \n and then \n would be eaten up .

Resources