I was working on a circular linked list problem and solved it.But i got stuck in other problem. The program takes names of persons in circular linked list nodes and prints them.
My question is that program works fine if and only if the names are 4 characters or less.If the length of the names exceeds 4,it shows weird behaviour.
If the length of name is 5 characters,then the program is stuck on second iteration of the for loop of the initiate function.
If the length of name is 6 characters or more then program terminates immediately showing the names entered.
The source code is:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define SIZE 10
#define NUM_PER_LINE 3
typedef struct node
{
char name[SIZE];
struct node * next;
} CListNode;
void get_name(char *a);
void print_list(CListNode *end_ptr);
CListNode *initiate(int n);
CListNode *insert_at_end(CListNode *first,CListNode *end_ptr, char *a);
int main(void)
{
CListNode *list_end_ptr;
int n=6;
list_end_ptr=initiate(n);
print_list(list_end_ptr);
return 0;
}
void get_name(char *a)
{
char *aa=(char *)malloc(10*sizeof(char));
a=aa;
scanf("%s", a);
}
CListNode *insert_at_end(CListNode *first,CListNode *end_ptr, char *a)
{
CListNode *temp, *head=NULL;
head=first;
temp=(CListNode *) malloc(sizeof(CListNode));
end_ptr->next=temp;
strcpy(temp->name, a);
temp->next=head;
return temp;
}
CListNode *initiate(int n)
{
CListNode *end, *first=NULL,*ptr=NULL;
int i;
char new_name;
end=(CListNode *) malloc(sizeof(CListNode));
if (end==0) {
printf("Allocation error...\n");
exit(0); }
end->next=end;
for (i=0; i<n; i++) {
if (i<1) {
printf("Enter the name of the %d person: ", i+1);
get_name(&new_name);
strcpy(end->name, &new_name);
first=end;
}
else
{
printf("Enter the name of the %d person: ", i+1);
get_name(&new_name);
ptr=insert_at_end(first,end, &new_name);
end=ptr;
}
}
return end;
}
void print_list(CListNode *end_ptr)
{
int i=1;
CListNode *str_ptr;
if (end_ptr == NULL)
printf("\n List is empty");
else
{
str_ptr = end_ptr->next;
while (str_ptr != end_ptr)
{
printf("%s \t", str_ptr->name);
str_ptr = str_ptr->next;
if (i%NUM_PER_LINE==0) {
printf("\n");
}
i++;
}
printf("%s\n", str_ptr->name);
}
}
The problem is in your get_name function and the way you use it. Its signature assumes that the storage is already allocated, because you take a pointer, not a pointer to pointer. Your code ignores the allocation completely; on top of that, it passes a pointer to character.
Since you allocate name within the node, remove malloc, remove new_name, and pass name array to get_name:
void get_name(char *a) {
scanf("%9s", a); // Limit the size to 9 chars
}
...
printf("Enter the name of the %d person: ", i+1);
get_name(end->name);
Related
typedef struct inventory
{
char *name;
int quantity;
double price;
struct inventory* next_inventory;
} invent;
int main(void)
{
invent *one=malloc(sizeof(invent));
invent *two=malloc(sizeof(invent));
invent *three=malloc(sizeof(invent));
one->next_inventory=two;
two->next_inventory=three;
three->next_inventory=NULL;
one->name=malloc(256);
...(repeat two->name, three->name)
printf("name: ");
scanf("%s", one->name);
printf("qunatity: ");
scanf("%d", &one->quantity);
printf("price: ");
scanf("%lf", &one->price);
...(repeat scanf() for two, three)
while(one!=NULL)
{
printf("%s %d %.0f\n", one->name, one->quantity, one->price);
printf("check\n");
one=one->next_inventory;
}
free(one->name);
free(two->name);
free(three->name);
free(one);
free(two);
free(three);
return 0;
free(one->name); doesn't work. I checked another free(), using printf("check");, two->name, three->name, one ... its worked. Why only free(one->name) doesn't work? What can I do for solve this problem? Give me the advice.
You are using your actual 'one' variable to do the iteration, in the end you are trying to free(one) where one points to NULL.
You should not lose track of the address of the memory you requested to allocate, to be able to release that memory later with free.
I would use a temporary pointer to iterate:
invent* tmp = one;
while(tmp!=NULL)
{
printf("%s %d %.0f\n", tmp->name, tmp->quantity, tmp->price);
printf("check\n");
tmp=tmp->next_inventory;
}
// free all names and one, two, three.
In alternative:
you can define a function for printing:
void printAll(invent* one)
{
while(one!=NULL)
{
printf("%s %d %.0f\n", one->name, one->quantity, one->price);
one=one->next_inventory;
}
}
then in the main, call
printAll(one)
This works as the pointer is passed by value in the function and you won't lose the original address.
Here is a improved version of your program that includes also checking malloc return code:
#include <stdlib.h>
#include <stdio.h>
typedef struct invent
{
char *name;
int quantity;
double price;
struct invent* next_inventory;
} invent;
void enter(invent **s)
{
printf("name: ");
scanf("%s", (*s)->name);
printf("quantity: ");
scanf("%d", &(*s)->quantity);
printf("price: ");
scanf("%lf", &(*s)->price);
}
void *alloc(size_t size)
{
void *p;
p = malloc(size);
if (p == NULL)
{
perror("malloc");
exit(1);
}
return p;
}
int main(void)
{
invent *start;
invent *one;
invent *two;
invent *three;
one = alloc(sizeof(invent));
two = alloc(sizeof(invent));
three = alloc(sizeof(invent));
start = one;
one->next_inventory=two;
two->next_inventory=three;
three->next_inventory=NULL;
one->name=alloc(256);
two->name=alloc(256);
three->name=alloc(256);
enter(&one);
enter(&two);
enter(&three);
while(one != NULL)
{
printf("%s %d %.0f\n", one->name, one->quantity, one->price);
printf("check\n");
one=one->next_inventory;
}
free(start->name);
free(two->name);
free(three->name);
free(start);
free(two);
free(three);
return 0;
}
I am getting garbage value when I display the records.
I have to create a database of students in C using array of structures and without pointers.
Is there any other way of doing this?
How to use array of structures?
#include <stdio.h>
struct student {
char first_name[10],last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student);
void display(struct student);
void main() {
struct student S[10];
int n, i;
printf("Enter the number of records to enter : ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
accept(S[i]);
}
for (i = 0; i < n; i++) {
display(S[i]);
}
}
void accept(struct student S) {
scanf("%s", S.first_name);
scanf("%s", S.last_name);
scanf("%d", &S.roll);
scanf("%s", S.address);
scanf("%f", &S.marks);
}
void display(struct student S) {
printf("\n%s", S.first_name);
printf("\n%s", S.last_name);
printf("\n%d", S.roll);
printf("\n%s", S.address);
}
Everything in C is pass-by-value. Which means you are modifying variable copy in stack frame, while real variable passed as parameter remains untouched.
You have to pass an pointer to variable which you want to modify in function.
// Function declaration
void accept(struct student *);
// Call
accept(&S[i]);
// Usage in function via dereference operator
scanf("%s",S->first_name);
If you would like to enter unknown amount of records, you should use VLA (since c99) or dynamically allocate structures.
VLA
scanf("%d",&n);
struct student S[n];
Dynamic callocation
scanf("%d",&n);
struct student * S = malloc(sizeof(struct student) * n);
Because in your case, if user input more that 9 records you are touching outside of bounds, which has undefined behavior.
There are multiple issues in your code:
The standard prototype for main without arguments is int main(void)
You should allocate the array dynamically with calloc.
you should pass structure pointers to the accept and display functions instead of passing structures by value. Passing the destination structure by value is incorrect as the accept function cannot modify the structure in the main function, which remains uninitialized and causes garbage to be displayed. Note that it is actually undefined behavior to access uninitialized data so the program could behave in even worse ways.
You should provide scanf() with the maximum number of arguments to store into character arrays to avoid potential buffer overflows.
you should verify the return values of scanf() to avoid undefined behavior on invalid input.
you could use the %[^\n] scan set to allow embedded spaces in the address field.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct student {
char first_name[10], last_name[10];
int roll;
char address[20];
float marks;
};
void accept(struct student *sp);
void display(const struct student *sp);
int main(void) {
struct student *S;
int n, i, j;
printf("Enter the number of records to enter : ");
if (scanf("%d", &n) != 1)
return 1;
S = calloc(sizeof(*S), n);
if (S == NULL) {
return 1;
}
for (i = 0; i < n; i++) {
accept(&S[i]);
}
for (i = 0; i < n; i++) {
display(&S[i]);
}
free(S);
return 0;
}
void accept(struct student *sp) {
if (scanf("%9s%9s&d %19[^\n]%f",
sp->first_name, sp->last_name, &sp->roll,
sp->address, &sp->marks) != 5) {
printf("missing input\n");
exit(1);
}
}
void display(const struct student *sp) {
printf("%s\n", sp->first_name);
printf("%s\n", sp->last_name);
printf("%d\n", sp->roll);
printf("%s\n", sp->address);
printf("%f\n", sp->marks);
printf("\n");
}
I am trying to create a circular linked list in C.
But I haven't understood quite well the linked lists.
Well the program gets an int to a function called list_end_ptr which initialises the circular linked list and creates nodes for the int.
Then another function (insert_at_end) puts new nodes on at the end of the initialized list and returns the last node.
A 3rd function prints the linked list (print_list) by getting the end node and printing first the first entered name and finishes with the last.
The idea is to have only an end node and work only with this, but I can't make it work. I have managed to make it partially work, when I print the data are printed in reverse order of the name entry (from last entered to the first).
Any idea?
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define SIZE 10
#define NUM_PER_LINE 3
typedef struct node
{
char name[SIZE]; /* SIZE-1 χαρακτήρες και το '\0' */
struct node * next;
} CListNode;
void get_name(char *a);
void print_list(CListNode *end_ptr);
CListNode *initiate(int n);
CListNode *insert_at_end(CListNode *end_ptr, char *a);
int main(void) {
CListNode *list_end_ptr;
int n=6;
list_end_ptr=initiate(n);
print_list(list_end_ptr);
return 0;
}
void get_name(char *a)
{
char format[10];
sprintf(format, "%%%ds", SIZE-1);
scanf(format, a);
}
CListNode *insert_at_end(CListNode *end_ptr, char *a)
{
CListNode *temp, *head=NULL;
head=end_ptr->next;
temp=(CListNode *) malloc(sizeof(CListNode));
end_ptr->next=temp;
strcpy(temp->name, a);
temp->next=head;
return temp;
}
CListNode *initiate(int n) {
CListNode *end, *first=NULL;
int i;
char new_name;
end=(CListNode *) malloc(sizeof(CListNode));
if (end==0) {
printf("Allocation error...\n");
exit(0); }
end->next=end;
for (i=0; i<n; i++) {
if (i<1) {
printf("Enter the name of the %d person: ", i+1);
get_name(&new_name);
strcpy(end->name, &new_name);
first=end;
}
else
{
printf("Enter the name of the %d person: ", i+1);
get_name(&new_name);
insert_at_end(end, &new_name);
}
}
return end;
}
void print_list(CListNode *end_ptr)
{
int i=1;
CListNode *str_ptr;
if (end_ptr == NULL)
printf("\n List is empty");
else
{
str_ptr = end_ptr->next;
while (str_ptr != end_ptr)
{
printf("%s \t", str_ptr->name);
str_ptr = str_ptr->next;
if (i%NUM_PER_LINE==0) {
printf("\n");
}
i++;
}
printf("%s\n", str_ptr->name);
}
}
My friend you are not updating the end pointer for condition i>0.The very first node you create is very much right but when you code starts executing the else part of for loop, the end pointer is not manipulated correctly. Here is the corrected version of the code you have given
For the else part of for loop of the initiate function
else
{
printf("Enter the name of the %d person: ", i+1);
get_name(&new_name);
ptr=insert_at_end(first,end, &new_name);/*insert_at_end returns temp*/
end=ptr;
}
The insert at end function returns temp so that end pointer can be updated.
For the insert_at_end function just replace the line
head=end_ptr->next;
with
head=first;
Of course, you would have to pass the first pointer in call of the function as well.
So in short,you had almost done the job right and with minute modifications like:
insert_at_end function returned value should be put into a pointer which in turn is used to update end.
We end up with correct code.
Do not forget to update the prototype of function insert_at_end.It should be
CListNode *insert_at_end(CListNode *first,CListNode *end_ptr, char *a);
Generally, inserting at the end of a singly-linked list (which is what you have) is a matter of iterating through the next pointer until you get to a NULL value, and then create a node, and adjust the previous last node's next pointer to point to the new node.
The code includes <strings.h> but that should be <string.h>.
Also, where your current code has strcpy you should probably instead use strdup or strncpy to make sure you don't overrun your allocated SIZE for name.
There are a number of problems with this code, but this should get you started:
CListNode *initiate(int n) {
CListNode *end, *first;
int i;
char new_name[SIZE];
end = first = malloc(sizeof(*first));
if (first == NULL) {
printf("Allocation error...\n");
exit(0);
}
for (i=0; i<n; i++) {
printf("Enter the name of the %d person: ", i+1);
get_name(new_name);
insert_at_end(end, new_name);
}
return end;
}
I have come across this wierd and mysterous (at least to me) error that I am finding a very hard time finding. It gives me an error at the line where I call my function input(student_list1[MAX], &total_entries); where the compiler says:
incompatible type for agument 1 in 'input'
What am I doing wrong here? I sense it something very simple and stupid but I have gone through the code several times now without any avail.
#define MAX 10
#define NAME_LEN 15
struct person {
char name[NAME_LEN+1];
int age;
};
void input(struct person student_list1[MAX], int *total_entries);
int main(void)
{
struct person student_list1[MAX];
int total_entries=0, i;
input(student_list1[MAX], &total_entries);
for(i=0; i<total_entries; i++)
{
printf("Student 1:\tNamn: %s.\tAge: %s.\n", student_list1[i].name, student_list1[i].age);
}
return 0;
} //main end
void input(struct person student_list1[MAX], int *total_entries)
{
int done=0;
while(done!=1)
{
int i=0;
printf("Name of student: ");
fgets(student_list1[i].name, strlen(student_list1[i].name), stdin);
student_list1[i].name[strlen(student_list1[i].name)-1]=0;
if(student_list1[i].name==0) {
done=1;
}
else {
printf("Age of student: ");
scanf("%d", student_list1[i].age);
*total_entries++;
i++;
}
}
}
struct person student_list1[MAX] in the function argument is actually a pointer to struct person student_list1.
student_list1[MAX] you passed is a (out of bound) member of the array struct person student_list1[MAX]. Valid array index shoudl be between 0 to MAX - 1.
Change it to:
input(student_list1, &total_entries);
Note that here the array name student_list1 is automatically converted to a pointer to student_list1[0].
There are many things wrong with the code; this is my attempt at making it somewhat more robust:
#include <stdio.h>
#include <string.h>
#define MAX 10
#define NAME_LEN 15
// use a typedef to simplify code
typedef struct person {
char name[NAME_LEN];
int age;
} person_t;
// size qualifier on student_list is redundent and person_t* does the same
void input(person_t *student_list, int *total_entries);
int main(void)
{
person_t student_list[MAX];
int total_entries, i;
// pass array and not the non-existent 'student_list[MAX]' element
input(student_list, &total_entries);
for(i=0; i<total_entries; i++)
{
// age is an int, not a string so use %d
printf("Student 1:\tName: %s.\tAge: %d.\n", student_list[i].name, student_list[i].age);
}
return 0;
} //main end
void input(person_t *student_list, int *total_entries)
{
int done = 0, i = 0;
*total_entries = 0;
while (i < MAX) {
printf("Name of student: ");
// use NAME_LEN instead of strlen(list[i].name) because latter is
// probably not initialized at this stage
if (fgets(student_list[i].name, NAME_LEN, stdin) == NULL) {
return;
}
// detect zero-length string
if (student_list[i].name[0] == '\n') {
return;
}
printf("Age of student: ");
scanf("%d", &student_list[i].age);
// read the newline
fgetc(stdin);
*total_entries = ++i;
}
}
input(student_list1[MAX], &total_entries); shoud be input(student_list1, &total_entries);.
In C,
void input(struct person student_list1[MAX], int *total_entries);
equals
void input(struct person *student_list1, int *total_entries);
I'm trying to create an array to hold an int, then when another int is to be added increase it in size to hold another int.. and so on..
I know it's not an efficient use of realloc, but it's proof on concept more than anything else. Just to get it working would allow me to optimise it and be able to apply it to something useful. A working example. The problem comes when i call the print function and it just segfaults. Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef char String[100];
void begin(int *);
void add(int *, int);
void print(int *);
int tempcount=0;
int main(void)
{
int *n=NULL;
String menu;
begin(n);
while(true)
{
scanf("%9s", menu);
if(!strcmp("a", menu)) //add
{
int i=0;
scanf("%d", &i);
add(n, i);
}
else if(!strcmp("p", menu)) //print
{
print(n);
}
else if(!strcmp("q", menu)) //quit
{
free(n);
break;
}
}
return 0;
}
void begin(int *n)
{
n=malloc(sizeof(int));
if(n==NULL)
{
printf("Error in malloc!");
return;
}
n[0]=0;
printf("Added %d \n", n[0]);
}
void add(int *n, int numToAdd)
{
static int sizeCount=0;
sizeCount++;
tempcount=sizeCount;
int *temp;
temp=realloc(n, (sizeCount+1) * sizeof(int));
if(temp==NULL)
{
printf("Error in realloc!");
return;
}
n=temp;
n[sizeCount]=numToAdd;
printf("Added %d \n", n[sizeCount]);
}
void print(int *n)
{
int i;
for(i=0; i<tempcount; i++)
{
printf("%d ", n[i]);
}
}
You need to pass a pointer to your pointers in add/begin so they can modify your pointer in main
begin(&n);
...
add(&n, i);
and your definition
void begin(int **n)
{
*n=malloc(sizeof(int));
if(*n==NULL)
{
printf("Error in malloc!");
return;
}
(*n)[0]=0;
printf("Added %d \n", (*n)[0]);
}
and
void add(int **n, int numToAdd)
{
static int sizeCount=0;
sizeCount++;
tempcount=sizeCount;
int *temp;
temp=realloc(*n, (sizeCount+1) * sizeof(int));
if(temp==NULL)
{
printf("Error in realloc!");
return;
}
*n=temp;
(*n)[sizeCount]=numToAdd;
printf("Added %d \n", (*n)[sizeCount]);
}
Right now what you're doing is modifying local copies of your pointer in begin/add, so when you change it in those functions it's not modifying your pointer n in main
Also, fun fact, if you pass NULL as the first parameter to realloc it acts like a malloc, so if you initialize n to NULL, you can simply call add without first doing a begin.
Check your function add - are you sure you update the pointer value?
Try with ** as a parameter - I think it will help.