Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c - realloc() on tokenized array: signal SIGABRT error

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';
}
like image 598
Kevin Welch Avatar asked Apr 29 '15 08:04

Kevin Welch


1 Answers

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_;
like image 70
Quentin Avatar answered Sep 23 '22 22:09

Quentin