c - realloc() для токенизированного массива: сигнал ошибки SIGABRT

В строке 56 я пытаюсь изменить размер массива:

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

Я получаю сообщение об ошибке:

(11972,0x7fff7ca4f300) malloc: * ошибка для объекта 0x100105598: неверная контрольная сумма для освобожденного объекта - возможно, объект был изменен после освобождения. * установите точку останова в malloc_error_break для отладки

Это задание по программированию для класса, мне было специально указано динамически распределять мои массивы, а затем расширять их по мере необходимости. Я много искал другую ветку в той же теме, которая не слишком продвинута для меня, чтобы понять, но пока не повезло ... Так что, надеюсь, я смогу получить некоторую помощь. Спасибо! Вот мой код:

#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';
}

person Kevin Welch    schedule 29.04.2015    source источник
comment
Одна вещь, которая меня беспокоит, это то, что tokenArray является указателем на указатель на char, но вы выделяете только с использованием sizeof(char), а не sizeof(char *). Таким образом, ваше начальное выделение представляет собой массив из десяти символов, а не десяти указателей на символ.   -  person Some programmer dude    schedule 29.04.2015
comment
Как упоминал @JoachimPileborg, это: char** inputArray = malloc(arrSize * (sizeof(char))); должно быть char** inputArray = malloc(arrSize * sizeof *inputArray);. Это защитит вас от самого себя и сделает выделение надлежащего размера. Эта схема работает всегда.   -  person unwind    schedule 29.04.2015
comment
Вау... вот и все! Большое спасибо вам обоим! Я действительно стараюсь публиковать здесь в крайнем случае: D   -  person Kevin Welch    schedule 29.04.2015
comment
Итак, если я правильно понимаю... поскольку массивы, естественно, являются указателями на адреса, когда я выделял свои массивы, я выделял их по размеру "char", даже если они фактически содержали бы адрес... так что " char *' даст размер адреса?   -  person Kevin Welch    schedule 29.04.2015
comment
Предупреждение: вы не должны приводить возврат malloc. Второе предупреждение: при вызове sizeof в malloc (и т.п.) вы всегда должны писать его как ptr = malloc(sizeof(*ptr) * ...); вместо ptr = malloc(sizeof(ptrtype*) * ...);.   -  person Eregrith    schedule 29.04.2015
comment
because arrays are naturally pointers to addresses это неправда. Вы сделали массив из char*-указателей, да, но также возможно сделать массив из char, int, struct и любого другого типа.   -  person maja    schedule 29.04.2015


Ответы (1)


1. Не использовать результат malloc и друзей.

В лучшем случае это бесполезно, а в худшем опасно.

2. Обратите внимание на размер, который вы malloc делаете.

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

Это не имеет смысла и, вероятно, случайно. Как правило, тип, на который вы указываете malloc, и указатель, который вы указываете на результирующее хранилище, должны отличаться только одной косвенностью. то есть:

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

Еще лучше эмпирическое правило, пусть компилятор разберется. sizeof может вывести тип, который он должен измерять, из выражения.

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

Это работает, потому что операнд sizeof является невычисленным контекстом. На самом деле указатель не будет разыменован, будет определен только его тип.
Примечание: скобки sizeof вокруг выражения не нужны, но я оставил их для ясности. Удалите их, как только вы освоитесь.

3. Убедитесь, что размещение прошло успешно.

malloc и друзья вернутся NULL в случае беды. Вы должны проверить это.

4. Исправьте realloc

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

Это не правильно. Как упоминалось выше, если realloc завершится ошибкой, он вернет NULL и больше ничего не сделает. Это означает, что inputArray по-прежнему указывает на свое предыдущее хранилище. То есть до тех пор, пока вы не перечеркнете этот указатель только что возвращенным NULL realloc и не утечете указанное хранилище. Упс.

Всегда сохраняйте, проверяйте и затем назначайте результат realloc.

char **inputArray_ = realloc(inputArray, /*...*/);
if(!inputArray_) {
    /* Allocation failure, handle it and break out */
}
inputArray = inputArray_;
person Quentin    schedule 29.04.2015