5

On line 56, I'm trying to resize an array:

tokenArray = (char**) realloc(tokenArray, tokSize * (sizeof(char)));

I get an error:

(11972,0x7fff7ca4f300) malloc: * error for object 0x100105598: incorrect checksum for freed object - object was probably modified after being freed. * set a breakpoint in malloc_error_break to debug

This is a programming assignment for a class, I have been specifically instructed to dynamically allocated my arrays, and then expand as needed. I have searched extensively for another thread on the same that isn't too advanced for me to understand, no luck yet... So hopefully I can get some help. Thanks! Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_ROW_SIZE 81

void strInput(char str[], int numElem);


int main(int argc, const char * argv[])
{
    printf("Enter a string of any number of integers separated by spaces or tabs.\n");
    printf("Maximum string length is 80 characters.\n");
    printf("Enter an empty string to conclude input.\n");


    int arrSize = 10, tokSize = 10, i = 0, j = 0;

    char** inputArray = malloc(arrSize * (sizeof(char)));
    char** tokenArray = malloc(tokSize * (sizeof(char)));


    do {
        inputArray[i] = malloc(MAX_ROW_SIZE * sizeof(int));

        strInput(inputArray[i], arrSize);

        if ((inputArray[i][0] != '\0') && (i == (arrSize - 1)))
        {
            arrSize = arrSize * 2;
            inputArray = (char**) realloc(inputArray, arrSize * (sizeof(char)));
        }

        while (inputArray[i][j] != '\0')
        {
            printf("%c", inputArray[i][j]);
            j++;
        }
        j = 0;

        i++;
    } while (inputArray[i-1][0] != '\0');

    i = 0;

    while (inputArray[i][0] != '\0')
    {

        if ((tokenArray[j] = strtok(inputArray[i], " \t")))
            j++;
        while ((tokenArray[j] = strtok(NULL, " \t")))
        {
            if (j == (tokSize - 1))
            {
                tokSize = 2 * tokSize;

 //This is the line where I get the error
                tokenArray = (char**) realloc(tokenArray, tokSize * (sizeof(char)));
            }
            j++;
        }
        i++;
    }

    printf("printing the tokenized arrays: ");
    for (i = 0; i < j; i++)
        printf("%s ", tokenArray[i]);

    free(inputArray);
    free(tokenArray);

    return 0;
}

void strInput(char str[], int numElem)
{


    int j, k = 0;

    j = k;

    while ((str[k] = getchar()) != '\n')
    {
        k++;
    }

    if (str[k] == '\n')
        str[k] = '\0';
}
Kevin Welch
  • 1,488
  • 1
  • 9
  • 18
  • 4
    One thing that worries me is that `tokenArray` is a pointer to pointer to `char`, but you're only allocating using `sizeof(char)` and not `sizeof(char *)`. So your initial allocation is an array of ten *characters* and not ten pointers to character. – Some programmer dude Apr 29 '15 at 08:17
  • 2
    As mentioned by @JoachimPileborg, this: `char** inputArray = malloc(arrSize * (sizeof(char)));` should be `char** inputArray = malloc(arrSize * sizeof *inputArray);`. That protects you from yourself, and makes the allocation have the proper size. This pattern always works. – unwind Apr 29 '15 at 08:19
  • Wow... that's all it was! Thanks a lot both of you! I really try to post on here as an absolute last resort :D – Kevin Welch Apr 29 '15 at 08:19
  • So if I'm understanding this correctly... because arrays are naturally pointers to addresses, when I was allocating my arrays I was allocating them to the size of 'char' even though they would actually be holding an address... so 'char *' will give the size of an address? – Kevin Welch Apr 29 '15 at 08:21
  • 1
    Warning: You [should not cast](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) the return of malloc. Second warning: when calling `sizeof` in `malloc` (and the like) [you should always write it](http://stackoverflow.com/a/17258659/1151654) as `ptr = malloc(sizeof(*ptr) * ...);` instead of `ptr = malloc(sizeof(ptrtype*) * ...);`. – Eregrith Apr 29 '15 at 08:23
  • 1
    `because arrays are naturally pointers to addresses` that's not true. You made an array out of `char*`-pointers, yes, but it's also possible to make an array of `char`, `int`, `struct` and any other type. – maja Apr 29 '15 at 08:27

1 Answers1

5

1. Do not cast the result of malloc and friends.

It's useless at best and dangerous at worst.

2. Mind the size you are malloc'ing.

char** inputArray = malloc(arrSize * (sizeof(char)));

This makes no sense, and is probably accidental. As a rule of thumb, the type you are malloc'ing for and the pointer you're pointing at the resulting storage should differ by only one indirection. I.e :

char** inputArray = malloc(arrSize * sizeof(char*));
//  ^^ Double-pointer     vs     Single pointer ^

Better rule of thumb yet, let the compiler figure it out. sizeof can deduce the type it should measure from an expression.

char **inputArray = malloc(arrSize * sizeof(*inputArray));

This works because the operand of sizeof is an unevaluated context. The pointer won't actually be dereferenced, only its type will be deduced.
Side note : sizeof's parentheses are not needed around an expression, but I've left them for clarity. Remove them once you're comfortable with it.

3. Check that allocation was successful.

malloc and friends will return NULL in case of trouble. You should check for that.

4. Fix your realloc

inputArray = realloc(inputArray, /*...*/);

This is wrong. As mentioned above, if realloc fails, it will return NULL and do nothing else. This means that inputArray still points at its previous storage. That is, until you trump this pointer with the NULL realloc just returned, and leak said storage. Oops.

Always store, check, and then assign the result of realloc.

char **inputArray_ = realloc(inputArray, /*...*/);
if(!inputArray_) {
    /* Allocation failure, handle it and break out */
}
inputArray = inputArray_;
Community
  • 1
  • 1
Quentin
  • 62,093
  • 7
  • 131
  • 191