-1

I think I have troubles understanding the malloc function in C, despite reading many tutorials and even though it seems to make sense theoretical, I get destroyed when I am trying to do something practical.

Currently I understand malloc this way: It's a function to reserve memory. So I tried this:

   char *str;

   /* Initial memory allocation */
   str = malloc(3);
   strcpy(str, "somestring");
   printf("String = %s\n", str);

   /* Reallocating memory */
   str = realloc(str, 15);
   strcat(str, ".com");
   printf("String = %s", str);

   free(str);

   return(0);

The output is:

String = somestring
String = som(2-3 strange characters).com

I know I should not malloc 3, rather the string size +1(null terminator). However the strange thing is, I never get any errors in the first line, in this case "somestring" is always displayed correctly. Just the second part, bugs out. When I delete the realloc part, everything works fine, even though in theory, it shouldn't. Do I understand something wrong or can somebody please explain this behaviour?

RandomUser42
  • 109
  • 8
  • [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior) is *undefined* but [scary](https://stackoverflow.com/a/25636788/841108).... – Basile Starynkevitch Jan 06 '18 at 20:25
  • 1
    Writing into memory you don't legally have access to makes your program have undefined behavior. An error is one manifestation of undefined behavior, but "working correctly and then acting weird" is also a valid manifestation. That's why you shouldn't write to memory you aren't supposed to. – StoryTeller - Unslander Monica Jan 06 '18 at 20:25
  • 1
    Undefined behaviour means undefined results. Just do it right in the first place. IMO a question that asks "why didn't I fall over when I tripped" is stupid. The answer is "because you didn't". – Weather Vane Jan 06 '18 at 20:25
  • @WeatherVane yeah, but if I would have tripped, I would have fallen to the ground, and not started flying into the air like in C. But kk I think I understand undefined behavior now :) – RandomUser42 Jan 06 '18 at 20:30
  • Just stop doing stuff you know is wrong. – Martin James Jan 06 '18 at 20:46
  • @MartinJames I knew it was wrong, but it didn't give me the expected result... – RandomUser42 Jan 06 '18 at 20:56
  • How could it have given an expected result, if is was wrong? – Weather Vane Jan 06 '18 at 21:14
  • "When I delete the realloc part, everything works fine, even though in theory, it shouldn't." Why do you think it shouldn't? If you drive faster than the speed limit, do you automatically get a fine? C is like that, if you break the rules - sometimes there are no ill repercussions. Sometimes there is. So - don't break the rules and code will behave as expected. – chux - Reinstate Monica Jan 06 '18 at 22:47
  • @WeatherVane well Right/Wrong is just a social expression, for something working the way you want it to work. In this case I expected the first output, to at least cut off after 3 characters, or even a program crash :), but it didn't, thats the reason why I asked here. – RandomUser42 Jan 06 '18 at 23:41
  • @chux yes good comparison, however I thought the computer was quite static handling its memory etc, in comparison with speed limit(as you already pointed out), there is not always an inspection, therefore the result is not always static. But is it so wrong to drive a bit faster sometimes to get a better understanding for your car?/In this case for the malloc function? – RandomUser42 Jan 06 '18 at 23:50
  • @RandomUser69 Set aside legal. If you drive "a bit faster" than designed for a better understanding of the car, you may make a [genetic pool decision](http://www.darwinawards.com). – chux - Reinstate Monica Jan 07 '18 at 00:31
  • @chux never said it's a smart decision ^^, but you get a better knowledge/feeling for fast speeds, which is obviously not worth, since you have way more to lose than your driving license. However in my malloc scenario, I don't really lose anything, I just learned more about C. I am glad we discussed the difference. :) – RandomUser42 Jan 07 '18 at 01:04

3 Answers3

2

Exceeding an array's bounds, e.g. those bounds defined by a previous malloc, is undefined behaviour. After such an operation, all bets are off. The program might even function as intended, but it may also yield some non obvious things. Confer, for example, the definition of UB in this online C standard draft:

3.4.3

(1) undefined behavior behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements

(2) NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

...

So reserve enough memory, and this behaviour should turn into the intended one.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
1

Your brief description of malloc is not incorrect. It does reserve memory. More accurately stated, from the link:

"Allocates a block of size bytes of memory, returning a pointer to the beginning of the block."

(emphasis mine)

But that is not the only consideration for using it in preparation for creating a C string.
In addition to understanding malloc(), Undefined Behavior (1) is good to be aware of, and how at best will cause buggy behavior, but possibly much worse.

By creating memory for 3 bytes, and writing a string with more than two characters (and a NULL terminator) you have invoked undefined behavior (2). Sometimes it will seem to work, but others it will not. In this case, you have written to memory that you do not own. If that memory is not also concurrently owned by another variable. It is likely to appear to you that all is normal, as is demonstrated by the results you show in your post. But if it is owned, and being used by another variable, the operation of writing to that location will fail. The second of these scenarios is the better of the two. The first is especially bad because it will cause your program to appear fine, possibly for hours, but the first time a conflict occurs, it will fail.

Keep in mind also, the definition of a string in C is a null terminated character array:

char string[20];
char string2[3];
strcpy(string, "string content");//will always work
strcpy(string2, "string content");//may or may not appear to work

string would appear in memory as:

|s|t|r|i|n|g| |c|o|n|t|e|n|t|\0|?|?|?|?|?|

Where ? can be any value.

there is no guarantee what string2 will contain.

Regarding your statement: However the strange thing is, I never get any errors in the first line..., because undefined behavior(3) is by definition unpredictable, the following may or may not help you to see the effects, but because of the over exagerated values and assignments, it will likely cause an access violation at some point...

char shortStr[2][3] = {{"in"},{"at"}};//elements [0] & [1] will be provided memory locations close in proximity.
char longStr[100]={"this is a very long array of characters, this is a continuation of the same thing."}; 
strcpy(shortStr[0], longStr);

This will likely result in an error because shortStr[1], although not guaranteed, is in a memory location that will prevent the copy from happening without a memory access violation.

ryyker
  • 22,849
  • 3
  • 43
  • 87
0

The function malloc may reserve more bytes than you asked for, for example 16 when you asked for 3, for reasons pertinent to memory management. You don't own those other 13 bytes, but nobody else does either, so you might "get away with" using that memory without any conflict. Until you demo the product: then it will fail, for sure.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56