0

I'm confused as to how memory allocation works in different scenarios in C.

For example, let's say I've created:
char string[7];
char *store[8];

and then, I have "string" be "123456\0".

When I have store[0] = string;, store[0] successfully stores the address of the 1st character of "string", which when printed using %s correctly prints "123456".

But, when I do strcpy(store[0], string), I get a segmentation fault error because I'm not accessing memory that I'm allowed to touch.

However, when using the 1st method (store[0] = string), am I not already allocating and reserving memory to create store[0]? What's the difference in memory handling here?

Does store[0] not already exist in either situation, since I've created store[8] via char *store[8] in the beginning, which should produce an array of 8 strings full of (garbage) data?

Apologies if my question is unclear. Any help is greatly appreciated.

minorproblem
  • 61
  • 1
  • 9
  • During `strcpy`, `store[0]` is uninitialized. So you are trying to access a location that may not be valid which leads to undefined behavior. If you want to use `store[0]`, the either you have to allocate a memory and point that memory in `store[0]` or point `store[0]` to a valid memory (e.g. an array already declared). In the first case, you are overwriting the content of `store[0]` to a valid address (i.e. `string`), so consequent access (i.e. when you print) is safe – kuro Jun 23 '23 at 05:46
  • I think your equalization leads to undefined behaviour, on my machine I cant replicate the segmentation fault, are you adding the string terminator character \0 to the 123456 string? – Juan Jun 23 '23 at 05:53
  • Hi @Juan , yes I am adding the string terminator character \0. I forgot to include that in my original post. – minorproblem Jun 23 '23 at 05:57
  • The compiler will add a NUL terminator with string initialization for you: `char string[7] = "123456";`, no need to explicitly add `\0` at the end, the compiler will add it. Furthermore, you can do `char string[] = "123456"` and the compiler will generate an appropriately-sized array as well (7 long in this case). – yano Jun 23 '23 at 06:04

1 Answers1

4

string is an allocated array that can hold 7 char values. It is initially filled with random garbage values since you are not initializing it. You are then copying "123456" into it, thus storing valid values in it.

store is an allocated array that can hold 8 char* pointers. It is initially filled with random garbage pointers since you are not initializing it.

In store[0] = string;, string decays into a char* pointer to its 1st char, and then you are saving that pointer to the 1st element of store. Since store is allocated, assigning a char* to its 1st element is fine.

In strcpy(store[0], string), you are copying the content of string to the memory address where the 1st char* in store is currently pointing at. If that address is not valid to write to, a segfault occurs. If the char* pointer is uninitialized, or if string is uninitialized (or is not null-terminated), then the behavior is undefined.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I see, that’s really helpful. So if I’m understanding correctly, the segfault ultimately happens because store[0] originally has some random garbage address it’s pointing to, and therefore strcpy can’t copy string’s contents in a valid allocated address? – minorproblem Jun 23 '23 at 05:55
  • @minorproblem yes, exactly – Remy Lebeau Jun 23 '23 at 05:56
  • I’m now a bit confused about your mention of “decay”. Is this occurring because “string” itself as an array, is technically just the address to its own 1st element/character? And so store[0]=string is really the same as store[0]=(address of 1st char in string)? – minorproblem Jun 23 '23 at 06:04
  • @minorproblem C has the concept of "pointer-decay" where arrays exist as types but can be passed to functions that expect pointers or assigned to variables that are pointers. This works because all that a variable of type array is at runtime is pointer. The difference between a pointer and an array has observable consequences though, you can see it with the sizeof-operator. – julaine Jun 23 '23 at 06:11
  • @julaine I see. Thank you so much! I’m learning via Harvard’s cs50 course right now, and I’m starting to feel daunted by the increasing levels of abstraction. It’s hard to not feel discouraged or stupid sometimes. Excited to continue learning though! – minorproblem Jun 23 '23 at 06:20
  • @minorproblem - The confusion between pointers and arrays goes way back, and has been asked many times before. See [Is an array name a pointer?](https://stackoverflow.com/questions/1641957/is-an-array-name-a-pointer) – BoP Jun 23 '23 at 09:21