2

I am trying to create a program that does some operations on a dynamic string. The next method is supposed to set myString to an empty string.

Whenever I try to realloc() the struct with the string (just like in the line of code which was only added for demonstration purposes) it results in an error:

Heap block at 0000000000541E80 modified at 0000000000541E91 past requested size of 1.

What causes the problem? I started learning C only a few weeks ago, so please don't use advanced terms.

struct _MyString
{
    char* myString;
};


MyString * myStringAlloc()
{
    MyString *newMyString = (MyString*) malloc(0);
    if(newMyString == NULL)
    {
        return NULL;
    }
    newMyString->myString = "";
    newMyString = (MyString*) realloc(newMyString, 4);
    //some more code
    return newMyString;
}
user2979612
  • 177
  • 11
  • This question is clearly not a duplicate of the one suggested by @SouravGhosh. – Veltas Aug 11 '15 at 16:50
  • 1
    Standard warning: Do not cast `void *` as returned by `malloc` & friends. C is **not** C++! – too honest for this site Aug 11 '15 at 16:56
  • 1
    This question is not a duplicate because the issue is not with malloc(0) for a char* but rather his failure to properly allocate space for the entire struct. Also there is the issue where he is reallocating space for the entire struct when he should only be realloc the pointer to the char* member – dbenson Aug 11 '15 at 16:56
  • There is also a misconception going on which would be worth addressing: regarding needing to heap allocate structs on the stack. – Veltas Aug 11 '15 at 16:57
  • 1
    @dbenson As fas as I can see, the problem _starts_ with `malloc(0)` returning a non-NULL value and the dereference...... – Sourav Ghosh Aug 11 '15 at 16:58
  • 1
    @SouravGhosh I took the time to type out a more complete answer I feel actually addresses the OP's misconceptions surrounding pointers and allocation, none of which are addressed in the linked post. – dbenson Aug 11 '15 at 17:02
  • 1
    @SouravGhosh So is there any chance of you reopening this question for discussion? – dbenson Aug 11 '15 at 17:39
  • @dbenson don't get me wrong sir, but apart from the issue discussed in the linked question, other issue is elementary and probably discussed a plentiful already here. Still, if you insist, I can reopen it, I don't have any issue with that. Shall we wait for some more time for a third opinion from somebody else, what say? – Sourav Ghosh Aug 11 '15 at 18:03
  • 1
    @SouravGhosh It isn't too much of a big deal for me, I just already had the response typed in when the submit button locked up haha :-p I wish the OP had commenting powers so he could say something – dbenson Aug 11 '15 at 19:29
  • @SouravGhosh You were the one arguing the question you linked was not a duplicate. Please pay us the same respects as the people who opened your question! I think 2 people is enough, OP counts as a 3rd person I'm sure. No one else will ever see this question as people ignore [duplicate]s – Veltas Aug 11 '15 at 20:14
  • OP I am very interested to know how you came to believe this was the way to write C. If it is some online tutorial, I have an email to write... – Veltas Aug 11 '15 at 20:19
  • @Veltas I finished a university summer course a few days ago. They rushed through a material of a whole semester in just 3 weeks. The material is clear in theory, but it's far from being clear on practice... I haven't been commenting on this because my problem seemed to be solved with the help of the first answer. However, a lot of stuff remains unclear - now when I allocated a struct with a `char` pointer, how do I change it from `NULL` to an actual value, after reallocating the struct? – user2979612 Aug 12 '15 at 10:00
  • FYI the first answer ABSOLUTELY isn't an answer to your problem. It fixes it, but it doesn't explain that what you are doing completely misses the point of how the stack works in C. I recommend you ask @SouravGhosh to reopen it. If you have further questions beyond what you asked in this question, open a new question (and obviously be careful for duplicates). This question is NOT a duplicate, Sourav's been too quick to close on those grounds. – Veltas Aug 12 '15 at 10:37

1 Answers1

1

Try to use:)

MyString *newMyString = (MyString*) malloc( sizeof( struct MyString ) );

instead of

MyString *newMyString = (MyString*) malloc(0);
                                          ^^^^

According to the C Standard (7.22.3 Memory management functions)

If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

In your code snippet the program two times tries to use the pointer to access the object. The first time in this statement

newMyString->myString = "";

and the second time in this statement

newMyString = (MyString*) realloc(newMyString, 4);

when tries to copy the original object.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    Could address the misconception of OP better – Veltas Aug 11 '15 at 16:50
  • 2
    Do not cast `void *`. – too honest for this site Aug 11 '15 at 16:59
  • 1
    I do not believe the latter of your two-times violates the standard verb-age. The pointer is not being used to access any object. Rather the pointer's value is being sent to `realloc`, which should be acceptable, as it fulfills the requirements of `realloc` (the value shall be resultant from a memory allocation function result, or NULL). If this is not the case, or if it is unclear, it may make for an interesting question all on its own. – WhozCraig Aug 11 '15 at 19:40
  • @WhozCraig In the first case the object is accessed to set its data member. In the second case this data member is copied. – Vlad from Moscow Aug 11 '15 at 19:53
  • 1
    Where in `newMyString = (MyString*) realloc(newMyString, 4);` is there any *member* being accessed? We may be looking at two different things. I was looking at the "second time in this statement" snippet you posted, which does not deref `newMyString` at all. – WhozCraig Aug 11 '15 at 19:58
  • @WhozCraig When the data member is copied from the old memory extent to the new one. – Vlad from Moscow Aug 11 '15 at 20:00
  • 1
    I don't see such a copy happening when the original size request was `0`. Per the citation you provided, the return from `malloc(0)` is implementation-defined (NULL or otherwise). In either case, whatever it is, that line of code should be valid. It is *certainly* valid if the value was NULL, and I'm not convinced it is invalid when the result was an implementation-defined non-null. No argument whatsoever the first snippet is wrong (obviously). – WhozCraig Aug 11 '15 at 20:06
  • @WhozCraig How is the object copied in this case? How is the value of the data member preserved? – Vlad from Moscow Aug 11 '15 at 20:17
  • @VladfromMoscow: I agree with Whoz, it's totally legit to send a size-0 allocated pointer to `realloc()` (as it is legit to send `NULL` to realloc as well). While it is not violating the usage of `malloc(0)`, it is still obviously an incorrect line for trying to allocate 4 bytes as `newMyString`. – Veltas Aug 11 '15 at 20:32
  • @Veltas Could you cite the standard where there is written that a pointer tp an object of size 0 may be used with realloc? – Vlad from Moscow Aug 11 '15 at 20:46
  • @VladfromMoscow "How is the object copied in this case"? - *What object* ? I contend that a non-null result from `malloc(0)` must be something `realloc` can examine to determine (a) this was a valid allocation, and (b) has no actual object bytes (discounting whatever internal housekeeping the implementation needs). Out of all of this, that was my only point. "How is the value of the data member preserved" - the data member was not established correctly because of the *first* line of code. As I said, I concur with you that code is broken. I'm not talking about that. – WhozCraig Aug 11 '15 at 21:11
  • @WhozCraig The problem is that actually malloc never allocates 0 bytes. Usually it allocates at least 16 bytes. It is not easy to determine what is stored in this memory. And realloc indeed accesses the object. It can simply copy all allocated memory without bother whether it contains something useful or not. – Vlad from Moscow Aug 11 '15 at 21:35
  • That isn't a problem; that's an implementation detail. Whatever `malloc(0)` returns, or `realloc(ptr, 0)` for that matter, is implementation-defined. If it is non-null, I expect `realloc` to be cognisant that it represents no user-data, and as such no user-data would be copied, thus no user-object would be accessed. I'm going to have to craft a question on this after I do some hunting through the standard to see if anything flies in the face of my postulate. – WhozCraig Aug 12 '15 at 02:36