I am creating a linked list that contains nodes with the "dataItem" of a void pointer. The purpose of this is in order to be able for the Node to contain any kind of data. However, I am unable to access the void pointer's data, even when that data is casted to the correct type.
My code looks like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student
{
char stuName[51];
char stuMajor[5];
double GPA;
char stuID[10];
}student;
typedef struct Node
{
union{
void *dataPtr;
int countr;
}dataItem;
int link;
struct Node* next;
}node;
void readData(struct Node *);
void main(){
node head;
node temp;
readData(&temp);
student *ptr = (student *)(temp.dataItem.dataPtr);
printf("%s %d", ptr->stuName, ptr->GPA);//breaks here because unable to access memory
}
void readData(struct Node *link)
{
link = (node *)malloc(sizeof(node));
student *ptr = (student *)malloc(sizeof(struct Student));
printf("enter the student name : ");
fflush(stdin);
scanf("%[^\n]", ptr->stuName);
printf("enter the student's major : ");
fflush(stdin);
scanf("%[^\n]", ptr->stuMajor);
printf("enter the student GPA : ");
scanf("%lf", &(ptr->GPA));
printf("enter the student ID : ");
fflush(stdin);
scanf("%[^\n]", ptr->stuID);
link->dataItem.dataPtr = ptr;
}
I know I definitely have a pointer wrong somewhere I'm not unsure how. I also have the node within my readData function point to a new malloc of Node because I want a new node each time readData is called for when I implement the linked list further.
Your code is very broken,
You didn't include any header file, you need at least stdlib.h for malloc(), and stdio.h for printf() and scanf().
Your main() definition is wrong, because main() must return int.
You fflush(stdin) which is undefined behavior.
You ignore the return value from scanf().
You assume that malloc() always returns a valid pointer.
You called readData() which is not declared yet.
But the most important mistake, is that you passed node temp's address to readData() and you malloc()ed it, but you didn't return a pointer to it, thereby losing all the changes made inside readData() which will not work anyway because it's undeclared at the moment you called it.
I fixed your code, because I know that you didn't like my answer, but check out the fixes which are related to the answer, and now it works as I expected
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student
{
char stuName[51];
char stuMajor[5];
double GPA;
char stuID[10];
} student;
typedef struct Node
{
union{
void *dataPtr;
int countr;
} dataItem;
int link;
struct Node* next;
} node;
void readData(struct Node **link);
int main()
{
node *head;
student *ptr;
readData(&head);
ptr = head->dataItem.dataPtr;
if (ptr != NULL)
printf("%s\t%g", ptr->stuName, ptr->GPA);
return 0;
}
void readData(struct Node **link)
{
student *ptr;
if (link == NULL)
return;
*link = malloc(sizeof(node));
if (*link == NULL)
return;
memset(*link, 0, sizeof(node));
ptr = malloc(sizeof(struct Student));
if (ptr == NULL)
return;
printf("enter the student name : ");
if (scanf("%50[^\n]%*c", ptr->stuName) != 1)
ptr->stuName[0] = '\0';
printf("enter the student's major : ");
if (scanf("%4[^\n]%*c", ptr->stuMajor) != 1)
ptr->stuMajor[0] = '\0';
printf("enter the student GPA : ");
if (scanf("%lf%*c", &(ptr->GPA)) != 1)
ptr->GPA = 0;
printf("enter the student ID : ");
if (scanf("%9[^\n]%*c", ptr->stuID) != 1)
ptr->stuID[0] = 0;
(*link)->dataItem.dataPtr = ptr;
}
I also added some safety fixes to scanf() adding the length modifier to prevent buffer overflow, and also remove the trailing '\n' with "%*c" specifier, it will not work if multiple spaces follow the value, but you can test it meanwhile just pressing Enter/Return, if you want more sofisticated input, you should use something else instead of scanf().
This:
void readData(struct Node *link)
{
link = (node *)malloc(sizeof(node));
You throw away the link parameter value that was passed in, instead assigning it a new allocation via malloc. This is your most significant problem, I think. A simple fix would be to delete the line performing the malloc.
You want to pass a pointer to a pointer (or address of a pointer) to a node to the readData() function. readData allocates a new node and fills it; what happens in your code is that readData() gets a copy of the address of temp, overwrites the copy of this address with a new address, the one obtained from malloc (which is invisible to the calling code in main()) and then fills that malloc'ed object. Upon return from readData the malloc'ed object is inaccessible.
What you wanted to do is this:
void main(){
node head;
node *tempAddr; // pointer
readData(&tempAddr); // pass address of that pointer
and then use *tempAddr in main instead of temp.
void readData(struct Node **linkAddr)
{
node *link = *linkAddr = (node *)malloc(sizeof(node));
[...]
unwind would complain that you should not cast the result of malloc, but I think it's fine. I also do not care about the return value of main, or its arguments.
Related
In the code below I tried to use printf and scanf to get data from user and store them inside a struct i defined called node.
The programme works fine for the first prompt, but as soon as the user input name, the programme ends with printing Age:salary:
Can anyone help me with this?
On a side note, can anyone also help me to understand how to create a loop to store data in various nodes and store them together? (Not hard-code it one by one)
Thank you very much!!
typedef struct node
{
char *name;
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
Use a char[] for name,
for example:
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
If you want to get several users, loop for ever and ask if the user wants to add more data.
I have create a function to print the list
Console:
Name:Foo
Age:12
salary:12
Continue Y/N
Y
Name:Bar
Age:14
salary:14
Continue Y/N
Y
Name:John
Age:30
salary:45
Continue Y/N
N
John, 30, 45
Bar, 14, 14
Foo, 12, 12
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
static void printList(node *n)
{
while (n) {
printf("%s, %d, %d\n", n->name, n->age, n->salary);
n = n->next;
}
}
static node *get_nodes(void) {
node *list = NULL;
while (42) {
char c;
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = list;
list = tmp;
printf("Continue Y/N\n");
scanf(" %c", &c);
if (c == 'N')
break;
}
return list;
}
static void clearList(node *node) {
if (node->next) {
clearList(node->next);
}
free(node);
}
int main(void)
{
node *list = get_nodes();
printList(list);
clearList(list);
return 0;
}
You are trying to write to Uninitialized memory
This is a very common problem beginners face.
You are trying to store the name using char *name declaration.
Here name does not point to a valid memory location, that's why You program is not running as expected.
Even if name points to a valid memory address, you must have enough memory allocated to store the data.
You can use
#define BUFFER_SIZE 50
char name[BUFFER_SIZE];
You can use any buffer size as you like, and then store a string of that length - 1 in the name array. -1 is for the null termination character \0.
Using this declaration you are allocating memory of BUFFER_SIZE bytes and the name points to the first byte in that array.
This allocation happens on the stack not in the HEAP
For fix your bug, you should allocate memory of your char *.
First Way, when you create your struct.
typedef struct node
{
char name[200]; // You specify that your char * can save 200 char
int age;
int salary;
struct node * next;
}node;
or you can create init struct function
node *init_node()
{
node *test = null;
test->name = malloc(sizeof(char) * 200);
test->age = 0;
test->salary = 0;
test->node = null;
return test
}
I am trying to create a linked list in C and this post refers to the part where I try to assign a variable in a structure a string value that the user inputs. The program compiles perfectly yet if I use strcpy() instead of strdup() then I get unwanted output.
The program compiles fine and gives no warnings or errors. If strdup() is used then the program works as intended but I'd like to know why it doesn't work when strcpy() is used instead. When passing in strings for the names, when the list is printed it will occasionally print null and then terminate or it will instead print "Name:Name:Name:Name:Nam" or other such unpredictable errors. Any other comments or criticisms would be appreciated as well as I am just starting to learn the language, thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct addressBook {
char *name;
int age;
char *phoneNumber;
struct addressBook *next;
};
static struct addressBook *head = NULL;
static struct addressBook *current;
static struct addressBook *createNew;
//function prototypes
void addNode(void);
struct addressBook * createNode(void);
void printAddressBook(void);
void printStats(void);
int main(void)
{
addNode();
addNode();
printAddressBook();
addNode();
addNode();
printAddressBook();
}
struct addressBook * createNode(void)
{
struct addressBook *newNode;
newNode = (struct addressBook *) malloc(sizeof(struct addressBook));
if (newNode == NULL)
{
puts("Memory error");
exit(1);
}
printf("\nEnter persons name: ");
char name[20];
scanf("%s", name);
strcpy(newNode -> name, name); //produces unpredictable results
//newNode -> name = strdup(name); Works fine with strdup
printf("Enter persons age: ");
scanf("%d", &newNode -> age);
printf("Enter persons phone number: ");
char phoneNumber[15];
scanf("%s", phoneNumber);
strcpy(newNode -> phoneNumber, phoneNumber); //produces unpredictable
results
//newNode -> phoneNumber = strdup(phoneNumber); Works fine with strdup
return(newNode);
}
void addNode(void)
{
createNew = createNode();
current = createNew;
current -> next = head;
head = current;
}
void printAddressBook(void)
{
struct addressBook *temp;
temp = head;
while(temp)
{
printf("Name: %s\nAge: %d\nPhoneNumber: %s\n\n\n",
temp -> name,
temp -> age,
temp -> phoneNumber);
temp = temp -> next;
}
}
When you define a pointer like char *name; it points to some random location as you haven't initialized it. It is illegal to write to the pointer and doing so will invoke Undefined Behavior.
strcpy basically writes the string to this random pointer location invoking UB.
strdup on the other hand, allocates the required memory dynamically for the string, copies the string to that location and then returns the start of the location. You can read/write to this memory location and hence, this is valid.
As part of an assignment, I am having a program read in the names and id of people from a file, and saving them in separate linked lists. I have a nested while loop to traverse the list until it reaches the end, and then assign the values at the end. Unfortunately the program keeps crashing while reading and it seems to revolve around the second while loop.
Here is the struct established before the main()
struct node
{
char name[50];
int id;
struct node *next;
}*start;
Here is the function itself:
void read()
{
int tempNum = 0, id, jack = 0;
char name[50];
struct node *temp, *right;
temp = start;
FILE *ifp = fopen("AssignmentOneInput.txt", "r");
while(fscanf(ifp," %s", &name) != EOF)
{
fscanf(ifp, " %[^,]s, %[^/n]d", &name, &id);
temp = (struct node *)malloc(sizeof(struct node));
strcpy(temp->name,name);
temp->id = id;
right = (struct node *)start;
printf("test number one\n");
while(right->next != NULL)
{
printf("test number two\n");
right = right->next;
}
printf("test number three\n");
right->next = temp;
right = temp;
right->next = NULL;
}
}
As for its implementation in the main function, it is the very first function called, so it looks a little like:
main()
{
read();
I guess thatstart is a global variable? Then it will be zero-initialized by the compiler and C runtime system. That means it will, as a pointer, be initialized to NULL. So when you use it uninitialized in your code it will be NULL and you have undefined behavior when you dereference the pointer. And undefined behavior is arguably the most common cause of crashes.
I have been hesitant to post a question about this because I'm worried about asking a stupid question, but here it goes:
I am currently trying to create a program that will take whole strings, put them into char arrays and transfer those char arrays to a linked list. I have everything working up to the point of actually putting the arrays into the linked list.
I initially tried to just create each node with the array itself, which was just giving me the first element of the array. Then I found that I need to use strcpy().
I'm not sure what is wrong at this point, but I think it's down to memory allocation because it's giving me a segfault. That is confusing however, because the memory allocation for rach node is already taken care of.
Thank you for any help, this part has been driving me crazy for a few hours now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
struct node {
char info;
struct node *link;
} *start;
void create(char[]);
void display();
void insert_end(char[]);
int main() {
int i;
start=NULL;
char data[SIZE];
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
create(data);
for(i=0; i<5; i++)
{
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
insert_end(data);
}
display();
return 0;
}
void create(char data[])
{
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
if (start == NULL)
{
strcpy(temp->info,data);
temp->link=NULL;
start=temp;
}
}
void display()
{
struct node *ptr;
ptr = start;
while (ptr!=NULL)
{
printf("%c", ptr->info);
ptr=ptr->link;
}
}
void insert_end(char data[])
{
struct node *ptr, *tempnode;
ptr = start;
while(1)
{
if(ptr->link != NULL)
{
ptr=ptr->link;
}
else
break;
}
tempnode=(struct node *)malloc(sizeof(struct node));
strcpy(tempnode->info,data);
tempnode->link=NULL;
ptr->link=tempnode;
}
As you stated you are using arrays, space needs to be reserved in the info member of the linked list structure. char type will only hold one character.
struct node {
char info[SIZE];
struct node *link;
} *start;
If info is an array, printf requires %s format modifier.
printf("%s\n", ptr->info);
info is a char not a char *.
Compile with -W -Wall, you'll see most of your mistakes.
I am trying to implement the Linked List data structure for my college course, but on executing the code the following line produces an EXC_BAD_ACCESS(code=1, address=0x8) error.
temp->next = (ptrtonode) malloc(sizeof(struct node));
Following is the code in its entirety.
#include <stdio.h>
#include <stdlib.h>
typedef struct node *ptrtonode;
typedef ptrtonode header;
struct node
{
int data;
ptrtonode next;
};
ptrtonode create(int n)
{
int i;
header temphead = NULL;
ptrtonode temp = temphead;
for(i=0;i<n;i++)
{
temp->next = (ptrtonode) malloc(sizeof(struct node));
printf("Enter data for node %d: ", i+1);
scanf("%d", &temp->next->data);
temp = temp->next;
}
temp->next = NULL;
return temphead;
}
int main(int argc, const char * argv[])
{
header head;
int n;
printf("How many nodes do you wish to create?");
scanf("%d", &n);
head = create(n);
}
Any help would be appreciated.
Thanks all!
On first iteration of the for loop inside the create() function temp is NULL, which is then dereferenced causing the failure (not malloc() causing the failure). You will need to restructure the code slightly to prevent dereferencing a NULL pointer.
Other points:
casting the return value of malloc() is not required.
check the result of scanf() to ensure n was assigned a valid integer (and confirm that the int is positive):
/* scanf() returns the number of assignments made,
which in this case should be 1. */
if (1 == scanf("%d", &n) && n > 0)
{
/* 'n' assigned a sensible value. */
}