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.
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
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 */);
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);
}
I thought arrays are inherently pointers
Array Vs pointer:
An array might decay to a pointer in expressions and function parameters, and array accesses might be rewritten by the compiler as pointer accesses, but they are not interchangeable. An array name is an address, and a pointer is the address of an address.
Why is this required?
Declaring a pointer only allocates memory for the pointer.
You can initialise a pointer in two ways:
Either with a string literal:
ptr = "abcd";
Originally, ptr was
indeterminate. But this changes
what it was pointing to such that
it now points to a string literal.
The compiler will store the
address of the first element of
the string literal in ptr.
If you were to do the same with an
array:
char s[] = "String";
and then try to change its value:
s = "String2";
/* error: assignment to expression
with array type */
It wouldn't compile, because
arrays, unlike pointers, are not
modifiable lvalues.
You can't change its value.
Or allocate memory for it and then
write to it.
errno = 0;
ptr = malloc (size);
if (!ptr) {
errno = ENOMEM;
perror ("malloc ()");
deal with error here...
}
Now you can use strcpy () to
copy to it.
Related
If understand my own code correctly I am allocating space for 3 pointers pointing to a data type ListNode and then looping three times and adding a number to each node.
I know that the nodes are not connected to one another
now when I try to access any node from the allocated space I get the error commented in the bottom of the code
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode {
int val;
struct ListNode *next;
} ListNode;
int main(void)
{
int nums[] = {2,3,4};
ListNode * ptr = (ListNode*)malloc(3*sizeof(ListNode*));
for (int i=0; i < sizeof(nums)/sizeof(nums[0]); i++ )
{
ListNode new;
new.val = nums[i];
ptr[i] = new;
}
printf("%d \n",ptr[0].val);
free(ptr);
return 0;
}
/*
Error:
malloc(): corrupted top size
Aborted (core dumped)
*/
why do I get this error and how to properly access each node in the allocated space
You're not allocating enough space:
ListNode * ptr = (ListNode*)malloc(3*sizeof(ListNode*));
Here you're attempting to dynamically allocate a 3 element of array of ListNode structs, but you're instead allocating space for 3 pointers to ListNode. These pointers are smaller that the structs, so you end up writing past the end of allocated memory, triggering undefined behavior and a crash.
You want to allocate space for 3 structs, not 3 pointers:
ListNode * ptr = (ListNode*)malloc(3*sizeof(ListNode));
Or better yet:
ListNode * ptr = (ListNode*)malloc(3 * sizeof *ptr);
As this doesn't depend on what the type of ptr is.
int nums[] = {2,3,4};
size_t k = sizeof(nums)/sizeof(nums[0]);
ListNode * ptr = malloc(k*sizeof(ListNode));
Do not cast the malloc's result for reasons you can find in many places, including on SO.
Allocate COUNT times sizeof(object), not sizeof(object*) bytes.
#include <stdio.h>
#include <stdlib.h>
typedef struct nodeWords
{
char * word;
int index;
struct nodeWords *left;
struct nodeWords *right;
} nodeWords;
int main(void)
{
nodeWords * node = malloc(sizeof(*node));
printf("%lu\n",sizeof(*node));
node->left = NULL;
node->right = NULL;
nodeWords * ihash = malloc(2 * sizeof(*ihash));
printf("%p \n", node->left);
//this part not working
ihash[0] = *node->left;
printf("%p\n",ihash[0]);
}
How can I assign node->left to ihash[0] and then be able to print out ihash[0], which should point to NULL?
There are two errors in your code and a few other 'minor issues' (I've commented these in the code posted below).
The first error is that you want to create an array of pointers to nodeWords, so you will need two stars in the declaration of ihash (one star will create an array of structure objects).
Second, in ihash[0] = *node->left;, you are dereferencing node twice (once with the preceding star operator, and once again with the -> operator.
The following code fixes these issues:
#include <stdio.h>
#include <stdlib.h>
typedef struct nodeWords {
char* word;
int index;
struct nodeWords* left;
struct nodeWords* right;
} nodeWords;
int main(void)
{
nodeWords* node = malloc(sizeof(*node));
printf("%zu\n", sizeof(*node)); // Should really use "%zu" for size_t
node->left = NULL;
node->right = NULL;
nodeWords** ihash = malloc(2 * sizeof(*ihash)); // You want an array of POINTERS so you need two ** in the type!
printf("%p \n", (void*)node->left); // Pedantic: %p expects a void*
//this part not working
ihash[0] = node->left; // The "*" preceding "node" was an error: the "->" inherentlt derefernces node
// ihash[0] = (*node).left; // An alternative way of dong the same thing
printf("%p\n", (void*)ihash[0]); // Pedantic: %p expects a void*
// Don't forget to free the allocated memory...
free(ihash);
free(node);
return 0; // Always good practice to put this EXPLICIT return statement in your "main"
}
I'm making a program where I save input strings from fgets in a list, they have a fixed maximum lenght but can also be shorter; i save them like this:
typedef char line[LINE_SIZE];
struct node{
line *t; //pointer and not just a variable so I can "detach" the allocation to do stuff
struct node *prev;
struct node *next;
};
but, in my program I just do malloc(sizeof(line)) which is an array with the maximum fixed lenght.
My question is, if I were to allocate something like malloc( strlen( str ) + sizeof( ( char )'\0' ) ) to precisely use only the memory needed, how can I point it?
Is it okay using a char* inside the node struct? Do I risk something?
I have heard about flexible arrays inside the structs but I don't want to put the array directly inside the struct, because for the program I need to be able to detach it and then point to it with another pointer
malloc() returns the address it allocated, you can assign the return value to a variable and point it. You don't need to always allocate maximum or the same size of memory even though the variable is the same member of a struct.
char* line=malloc(strlen(str)+1); // +1 for null terminate
strcpy(line, "This is a str"); // points the memory of returned
Using a char* in a struct is absolutely fine. Please treat a member of struct like a plain variable.
struct node
{
char* t;
struct node* prev;
struct node* next;
}
node n;
n.t = malloc(strlen(str) + 1); // it's fine.
strcpy(n.t, "This is a node"); // using the memory you allocated above
n.prev = n.next = NULL;
... // doing some processing
free(n.t); // don't forget to call free() when you're done using the memory.
For your purpose, you must allocate the node structure and the line fragment separately.
Depending on what the rest of the code assumes, you could allocate just the space for the string for each line instead of a full array, but you must change the node structure to use a char *t; instead of a line typedef. Note that it is very confusing to typedef arrays.
The only caveat is you must be careful when modifying these strings as you cannot add any characters at the end, nor insert any characters by moving contents beyond their allocated length. As a rule of thumb, if you reallocate these strings whenever you modify them, you should be safe.
Here is a simple example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *t; //pointer and not just a variable so I can "detach" the allocation to do stuff
struct node *prev;
struct node *next;
};
struct node *read_file(FILE *fp) {
char buf[128];
struct node *head = NULL, tail = NULL, *n = NULL;
while (fgets(buf, sizeof buf, fp)) {
buf[strcspn(buf, "\n")] = '\0'; // strip the trailing newline if present
n = malloc(sizeof(*n));
if (n == NULL)
abort();
n->prev = tail;
n->next = NULL;
n->t = strdup(buf);
if (n->t == NULL)
abort();
if (tail == NULL) {
head = n;
} else {
tail->next = n;
}
tail = n;
}
return head;
}
#include <stdio.h>
struct mychar{
char value;
struct mychar *nextPtr;
};
typedef struct mychar Mychar;
typedef Mychar *MycharPtr;
void insert(MycharPtr *, char );
void printlist(MycharPtr);
int main(){
MycharPtr startPtr = NULL;
char b = 'b';
insert(&startPtr, b);
printlist(startPtr);
}
void insert(MycharPtr *sPtr, char newvalue){
MycharPtr newlinkPtr;
if (*sPtr == NULL){
newlinkPtr->value = newvalue;
newlinkPtr->nextPtr = NULL;
}
*sPtr = newlinkPtr;
}
void printlist(MycharPtr currentPtr){
printf("%c", currentPtr->value);
}
I'm just starting by only adding one char. If I can't even do that, I can't go on doing else.
It gives me segmentation fault, but I don't really know why.
Also, I still don't get the reason why in insert call I should write & but in printlist call I shouldn't write &.
You haven't actually allocated memory for newlinkPtr. So you're just dereferencing and attempting to write to an uninitialized pointer, resulting in undefined behaviour.
In insert, you can modify it to:
MycharPtr newlinkPtr = malloc(sizeof *newlinkPtr);
if (!newlinkPtr) {
perror("malloc");
return;
}
...
This also, sort of, illustrates why typedef'ing a struct pointer could mislead and considered a bad practice. I'd suggest avoiding it.
I need to initialize a linked list using ints given from the main.c.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char ** argv)
{
int b = 128;
int M = b * 11; // so we have space for 11 items
char buf [1024];
memset (buf, 1, 1024); // set each byte to 1
char * msg = "a sample message";
Init (M,b); // initialize
I know what I have isn't correct, but it's the best I could come up with.
#include <stdio.h>
#include "linked_list.h"
struct node
{
int value;
struct node *next;
};
struct node* head;
struct node* tail;
void Init (int M, int b)
{
head = (struct node *) malloc(sizeof *head);
tail = (struct node *) malloc(sizeof *tail);
head->next = tail;
tail->next = tail;
}
I just cannot see how to initialize the linked list using the ints. Thank you.
Your list is described by a pointer to its head element.
Now you want to initialise the list so that it is usable. The default state is an empty list, i.e. one that does not have any nodes. So what you don't do is to allocate memory. Just do this:
struct node *head = NULL;
You have a NULL head, which means that you don't have any elements. When you add nodes, you create them with malloc and assign them via this pointer. If the head is NULL, it must be updated to point to the first node, whose next member must be NULL.
Remember: Most pointers just point to existing data. There's no need to allocate memory to such pointers. And make sure to always initialise pointers properly; they should either point to valid memory or be NULL to mean "not pointing to anything".