circular linked list and insert at end function in C - c

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;
}

Related

Passing a Structure by reference to a function that will dynamically create and fill a array of structures

I want to pass a structure pointer to a function that will dynamically create a array of structures at the location pointed to by the structure pointer that was passed. I am able to create and fill the array of structure successfully but when trying to print the data in the calling function using the pointer that was passed gives me a garbage values. Please help me know why my structure pointer is pointing to garbage and how can I access my data correctly.
The following is just some example code to demonstrate how the structure is passed and dynamically filled using malloc & realloc. this is INCORRECT method:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
int id;
char name[20];
float percentage;
};
void func(struct student *record);
int main()
{
struct student *record = NULL;
record = (struct student *)malloc(sizeof(struct student));
func(record);
if(record != NULL)
{
for(int i=0; i<2; i++)
{
printf(" 1 Id is: %d \n", record[i].id);
printf(" 1 Name is: %s \n", record[i].name);
printf(" 1 Percentage is: %f \n", record[i].percentage);
printf("\n");
}
}
else
{
printf("record pointer is null");
}
return 0;
}
void func(struct student *record1)
{
for(int i=0; i<2; i++)
{
if(i)
{
record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));
}
record1[i].id=1;
strcpy(record1[i].name, "Raju");
record1[i].percentage = 86.5;
}
}
The following is a similar example using double pointer which is the CORRECT way to do this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
int id;
char name[20];
float percentage;
};
void func(struct student **record);
int main()
{
struct student *record = NULL;
func(&record);
if(record != NULL)
{
for(int i=0; i<2; i++)
{
printf(" 1 Id is: %d \n", record[i].id);
printf(" 1 Name is: %s \n", record[i].name);
printf(" 1 Percentage is: %f \n", record[i].percentage);
printf("\n");
}
}
else
{
printf("record pointer is null");
}
free(record);
return 0;
}
void func(struct student **record1)
{
*record1 = (struct student *)malloc(sizeof(struct student));
for(int i=0; i<2; i++)
{
if(i)
{
*record1 = (struct student *)realloc(*record1,sizeof(struct student)*(i+1));
}
(*record1)[i].id=1;
strcpy((*record1)[i].name, "Raju");
(*record1)[i].percentage = 86.5;
}
}
Your first solution,
record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));
works as long as realloc does not have to move the pointer! That is, realloc just expands the memory area it gave earlier to record1. Should, at some later stage, realloc be required to give you another piece of memory, then the earlier pointer record in main will become invalid and could now contain your "garbage".
As you were thinking, you need a double pointer to be able to see the changed pointer in main. You were nearly there, just a typo:
*record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));
in the above line the second occurrence of record1 must also be dereferenced, so *record1 because you must give realloc the original pointer.
Oh, and don't cast the result of malloc! Although the compiler does not complain, it can cause future problems.

Searching for string in linked list and getting all variables

As I said i have problems with linked list.
#include <stdio.h>
#include <stdlib.h>
#define MAX 30
typedef struct elem{
char name[MAX];
int statistic;
int price;
struct elem *next;
struct elem *prev;
} shop;
I have function with search for word in a linked list and then i want to get all variables as tmpname,tmpstatistic and tmpprice in main and use them for other things.
void search(shop *first, char word[MAX], char tmpname[MAX], int tmpstatistic, int tmpprice)
{
while (first!=NULL && strcmp(first->name, word) != 0)
{
first = first->next;
}
if (first != NULL && strcmp(first->name, word)==0)
{
printf("%s found! \n", word);
printf("%s \n", first->name);
printf("%d \n", first->statistic);
printf("%d \n", first->price);
tmpname=first->name;
tmpstatistic=first->statistic;
tmpprice=first->price;
}
}
When i print them in function it works but when i want to print tmp ones in main they are wrong.
If you could help me what to do to get good tmp variables in main. Im not really good at coding :/
Well, your function takes the tmpname, tmpstatistic and tmpprice parameters by value. It means that essentially what you pass in main is copied and the copies are assigned meaningful values in your function but the variables you passed in main remain unchanged. Pass those parameters by pointer!
void search(shop *first, char word[MAX], char** tmpname, int* tmpstatistic, int* tmpprice)
And then use, for example,
*tmpstatistic=first->statistic;
You have to pass pointers to your function search to get values out. So you can set the result where the pointer refers to.
void search(shop *first, char word[MAX], char **tmpname, int* tmpstatistic, int* tmpprice)
// ^ ^ ^
{
while (first!=NULL && strcmp(first->name, word) != 0)
{
first = first->next;
}
if (first != NULL && strcmp(first->name, word)==0)
{
printf("%s found! \n", word);
printf("%s \n", first->name);
printf("%d \n", first->statistic);
printf("%d \n", first->price);
*tmpname=first->name; // assigne pointer to first->name where tmpname refers to
*tmpstatistic=first->statistic; // assigne first->statistic where tmpstatistic refers to
*tmpprice=first->price; // assigne first->pricewhere tmppricerefers to
}
}
If you need a copy of "name" use strcpy( *tmpname, first->name );
Call it like this:
search(first,word[MAX],&tmpname, &tmpstatistic, &tmpprice);
An other solution is to return a pointer to thefound element in list, or NULL if you didn`t find it:
shop* search(shop *first, char word[MAX])
{
while (first!=NULL && strcmp(first->name, word) != 0)
{
first = first->next;
}
return first; // If you didn't find word in list, first is NULL, else first is the found elment
}

When freeing a pointer for a nested struct getting Segmentation fault

This is my code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define NAMESIZE 20
#define LINESIZE 1024
typedef struct name name;
struct name
{
char last[NAMESIZE]; /* last name */
char first[NAMESIZE]; /* first name*/
};
typedef struct record record;
struct record
{
name name;
int score;
};
typedef struct record_list record_list;
struct record_list
{
record *data; /* the dynamic array of records */
size_t nalloc; /* number of records allocated */
size_t nused; /* number of records in use */
};
void list_init(record_list *list)
{
list -> data = 0;
list -> nalloc = 0;
list -> nused = 0;
}
int list_insert(record_list *list, const record *rec)
{
size_t newSize;
record *tmp;
if(list -> nalloc == list -> nused)
{
if(list -> nalloc == 0)
{
newSize = 1;
}
else
{
newSize = 2 * list -> nalloc;
}
tmp = realloc(list -> data, newSize * sizeof(record));
if(tmp == 0)
{
return 0;
}
list -> data = tmp;
list -> nalloc = newSize;
}
list -> data[list -> nused++] = *rec;
return 1;
}
void list_destroy(record_list *list)
{
printf("Attempting Deletion");
free(list->data);
free(list->nalloc);
free(list->nused);
list -> data = 0;
list -> nalloc = 0;
list -> nused = 0;
}
int main(void){
record_list list;
record *r;
name n;
int score;
char input[NAMESIZE];
char name[NAMESIZE];
char lname[NAMESIZE];
list_init(&list);
while(input != NULL) {
printf("Please enter a value for Name: ");
scanf("%s", input);
strcpy(input, name);
printf("Enter last name: ");
scanf("%s", input);
strcpy(input, lname);
printf("Enter score: ");
scanf("%d", &score);
r=(record*)malloc(sizeof(record));
if(r == NULL){
printf("There isn't enough memory.\n");
}
strcpy(n.first, name);
strcpy(n.last, lname);
r -> name = n;
list_insert(&list, r);
printf("\n");
printf("Choose next action:\n");
printf("\tTo add more type \"add\";\n");
printf("\tTo delete all records type \"del\";\n");
scanf("%s", input);
if(strcmp(input, "del") == 0){
list_destroy(&list);
printf("Deleted");
break;
}
}
return 1;
}
I am working on a small lab exercise where we make a struct, fill it and clear it if the user needs to. Yesterday everything worked but today I seem to either have not saved it or broke something because I am getting a ton of errors.
Here is an example of the error I'm getting:
Essentially when I call a method
void list_destroy(record_list *list);
it crashes before reaching the first print statement which means I am doing something wrong with the method call.
Summarized question: What could be causing the segmentation fault (where am I accessing incorrect memory) Or how else can I clear my struct memory without using free?
Thank you very much.
This should tell what your problem is:
code.c: In function 'list_destroy':
code.c:74: warning: passing argument 1 of 'free' makes pointer from integer without a cast
code.c:75: warning: passing argument 1 of 'free' makes pointer from integer without a cast
You're trying to free int fields. You can't free them because they are not pointers to memory blocks.
So, remove these lines of code:
free(list->nalloc);
free(list->nused);

Printing Names using Circular Linked List

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);

Realloc an int array

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.

Resources