Проблемы перераспределения при назначении строки динамическому массиву целых чисел

По сути, я пытаюсь преобразовать набор входных данных char в целые числа и назначить их динамическому массиву целых чисел. Строковый ввод и токенизация работают нормально. Проблема (из того, что я могу сказать), похоже, связана с перераспределением массива int; после двойного перераспределения массива указатель на массив int возвращает NULL.

Что я пытался сделать, так это удваивать размер массива int каждый раз, когда количество токенов встречается или превосходит (размер, деленный на sizeof(int)). Оператор realloc работает каждый раз, когда выполняется это условие.

Я думал, что использование указателя на указатель было окончательным решением этой проблемы. Бьюсь об заклад, это какая-то действительно очевидная проблема, но я в своем уме здесь. Если вы потребуете каких-либо дополнительных разъяснений, я постараюсь изо всех сил. Поймите, что я сдавал C только один семестр и большую часть пути боролся.

Кроме того, по правде говоря, это было частью классного задания, которое с тех пор прошло. Я бы предпочел объяснение того, что не так, а не полный код, если это нормально.

У меня много операторов printf, поэтому прошу прощения за беспорядок.

РЕДАКТИРОВАТЬ: заменены все экземпляры newArray в функции input() на *resize. Однако я никогда не пробовал присваивать значения через указатели указателям, поэтому не стесняйтесь поправлять меня синтаксическим примером, если вы знаете, как я ошибся. Здесь возникает ошибка сегментации:

for (k = (numElem - count); k < numElem; k++)
{
    printf("\nk = %i\n", k);
    printf("j = %i\n", j);
    printf("numElem = %i\n", numElem);
    printf("results[j]: %s\n\n\n", results[j]);

    /* Segmentation fault regardless of what is assigned
    to *resize[k]. */
    *resize[k] = atoi(results[j]); // PROBLEM HERE
    j++;
}

Исходный код был обновлен, чтобы отразить это. Чтобы сделать этот смехотворно длинный пост немного более сдержанным, давайте заявим, что я сделал это в main():

    int *newArray = malloc(MAXTOKEN * sizeof(int));

    input(&newArray);  

    free(newArray);  

Идем дальше.

/* String input takes in char values,
tokenizes them, converts the results
to int, assigns them to newresizeay. */
int input(int **resize)
{
    int i, j, k, count;

    int numElem = 0;
    int currentSize = MAXTOKEN;

    char str[MAXSTRING];
    char *results[MAXTOKEN];

    /* This entire loop takes place at least once,
    provided the first input isn't NULL. */
    do
    {     
        i = 0, j = 0, k = 0;

        /* Char input process. Takes place until the user
        presses ENTER. */
        printf("Input integer values separated by spaces, or "
            "press ENTER to exit.\n");   
        while ( ((str[i] = getchar() ) != '\n') && (i < MAXSTRING) )
            i++;
        printf("\n\n");

        str[i] = '\0';


        /* Tokenization of the chars that were input */
        count = 0;

        if (results[0] = strtok(str, " \t"))
            count++;

        while (results[count] = strtok(NULL, " \t") )
            count++;


        /* numElem = 1 if the first input prompt established
        str[0] as NULL */
        if ( (count < 1) && (numElem < 1) )    
            count = 1;

        numElem += count;

        printf("numElem: %i\ncurrentSize: %i\n", numElem, currentSize);

        /* If the number of elements to assign meet or surpass
        the amount of [memory / sizeof(int)], exponentially
        increase the size of the int resizeay. */
        if ( numElem >= currentSize )
        { 
            *resize = realloc(*resize, (currentSize) * sizeof(int));
            if (*resize == NULL)
                printf("\n\nYep, it threw up.\n\n");
            currentSize *= 2;
        }


        printf("\nSize should be: %i\n", currentSize * 4);
        printf("Actual size: %d\n", _msize(*resize));


        /* The tokenized chars are converted to integers and
        assigned to the int resizeay. */
        for (k = (numElem - count); k < numElem; k++)
        {
            printf("\nk = %i\n", k);
            printf("j = %i\n", j);
            printf("numElem = %i\n", numElem);
            printf("results[j]: %s\n\n\n", results[j]);

            *resize[k] = atoi(results[j]); // PROBLEM HERE
            j++;
        }

        for (i = 0; i < numElem; i++)
            printf("resize[%i]: %i\n", i, *resize[i]);               

        printf("\n\n\n");      

    } while (str[0] != NULL);   

}

person user3109954    schedule 17.12.2013    source источник
comment
Я не изучал это глубоко, но это похоже на проблему с повреждением кучи.   -  person Jabberwocky    schedule 17.12.2013


Ответы (3)


Входная функция получает как resize, так и arr. main отправляет один и тот же указатель обоим. Это ошибка.

При изменении размера resize arr остается прежним и может указывать на недопустимый адрес (когда realloc возвращает другой адрес).

Как исправить: удалите аргумент функции arr и используйте только resize.

person egur    schedule 17.12.2013
comment
Так что мне пришлось бы присваивать значения atoi как * resize [i] = atoi (результаты [j])? Когда я сделал это, первое значение нового массива int появилось просто отлично, но последовательные записи аварийно завершают работу при попытке присвоения последовательного индекса. Я отредактирую свой пост в ближайшее время. - person user3109954; 17.12.2013
comment
Также вы можете объявить int* arr = *resize; и работать с ним. Обновляйте размер только перед возвратом. realloc будет работать на arr. - person egur; 17.12.2013
comment
Я бы сказал более профессионально: я сделал именно то, что вы предложили, и все работает отлично. Сказать, что я благодарен, это ничего не сказать. Я был одержим этим, и теперь я могу отдохнуть. - person user3109954; 17.12.2013

Когда вы вызываете функцию realloc, если новый блок памяти меньше предыдущего, он сохранит исходное состояние, указывающее на блок памяти, который использовался предыдущим. Если новый блок памяти больше предыдущего, система перераспределит память на куча, и предыдущая память освобождается.

person qdd    schedule 17.12.2013

Среди прочих проблем:

char *results[MAXTOKEN];

должно быть

char *results[MAXTOKEN + 1];

потому что здесь максимальное значение count будет MAXTOKEN в этом цикле:

while (results[count] = strtok(NULL, " \t") )
  count++;

а также

char str[MAXSTRING];

это довольно страшно, потому что как только пользователь введет более MAXSTRIN (=11) символов, не нажимая Enter, вы получите переполнение буфера.

person Jabberwocky    schedule 17.12.2013