The following code below runs without a seg fault
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *data;
struct node *next;
};
int main(void)
{
struct node *head = malloc(sizeof(struct node));
head->data = "test";
printf("data: %s\n", head->data);
return 0;
}
when I switch the code to so
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *data;
struct node *next;
};
int main(void)
{
struct node *head = malloc(sizeof(struct node));
strncpy(head->data, "test", 512);
printf("data: %s\n", head->data);
return 0;
}
I receive a seg fault and am forced to switch my node property data to be of type char data[512]. Why is this required? I thought arrays are inherently pointers, so this behavior is not making sense to me.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char data[512];
struct node *next;
};
int main(void)
{
struct node *head = malloc(sizeof(struct node));
strncpy(head->data, "test", 512);
printf("data: %s\n", head->data);
return 0;
}
I expected that both pointers and arrays could be assigned string values in the same way.
CodePudding user response:
In this statement
head->data = "test";
the string literal having the array type char[5]
is implicitly converted to pointer to its first element and this pointer is assigned to the pointer head->data
.
In this statement
strncpy(head->data, "test", 512);
you are using an uninitialized pointer head->data
and trying to copy the whole string literal to the memory pointed to by that pointer with an indeterminate value. That invokes undefined behavior.
I thought arrays are inherently pointers, so this behavior is not making sense to me.
Arrays are not pointers. They can be implicitly converted to pointers to their first elements in most situations but this does not mean that arrays are pointers.
Consider the simple demonstration program below.
#include <stdio.h>
int main( void )
{
char data[512];
char *p = data;
printf( "sizeof( data ) = %zu\n", sizeof( data ) );
printf( "sizeof( p ) = %zu\n", sizeof( p ) );
}
Its output might look like
sizeof( data ) = 512
sizeof( p ) = 8
CodePudding user response:
In the second snippet (the one that crashes), you allocate memory for the node
struct, which includes the pointer data
. However, this pointer is never initialized, and it points to some arbitrary memory address (or just NULL
), meaning that writing to it is undefined behavior, and indeed likely to just segfault.
For it to point to a valid memory address, you'll have to explicitly allocate it:
struct node *head = malloc(sizeof(struct node));
head->data = malloc(sizeof(char) * 512 /* or some other size, of course */);
CodePudding user response:
Why is this required? I thought arrays are inherently pointers, so this behavior is not making sense to me.
Pointers are just pointers and the only memory they occupy is the memory required to store an address. If you want a pointer to point at dynamically allocated memory, you need to allocate it yourself.
Example:
struct node {
char *data;
struct node *next;
};
struct node *create_node(const char *str) {
struct node *nn = malloc(sizeof *nn);
if(nn) {
nn->data = strdup(str); // allocate strlen(str) 1 bytes and copy the string
if(nn->data) { // strdup was successful
nn->next = NULL;
} else { // strdup failed
free(nn);
nn = NULL;
}
}
return nn;
}
void destroy_node(struct node *n) {
free(n->data);
free(n);
}