проблемы с вводом данных и malloc в C - PullRequest
0 голосов
/ 15 сентября 2011

Я новичок в C и у меня небольшая проблема с моим кодом:

int i, n;
int *arr;
while(n != 0) {
    scanf("%d", &n);
    if(n == 0)
        exit(1);
    else {
        arr = (int*) malloc(sizeof(int) * n);
        for(i = 0; i < n; i++)
            scanf("%d", &arr[i]);
    } //end if
} //end while

Я пытаюсь сделать массив размером n, и я хочу остановитьчтение, когда я получаю '0', например, если я ввожу:

3
2
2
5
2
6
7
0

Я хочу массив размером 3 со значениями 2, 2, 5, массив 2 со значениями 6 и 7 и выход, потому чтоиз 0 * Извините, я пропустил важную часть, я думаю ... В моем коде вызовите calc (), где я посылаю arr, сразу после scanf ("% d", & arr [i]) и затемя верну значение, а затем, если следующие значения, например, 2 не равны 0, я прочитаю, создам новый массив, отправлю arr, выведу результат на консоль, и снова, если следующее значение будет равно 0, оно завершится.* Не могли бы вы, ребята, сказать мне, где я не прав?

Ответы [ 4 ]

3 голосов
/ 15 сентября 2011

Ты почти у цели!

Вы создаете новые массивы в arr, но это единственный указатель, поэтому он может ссылаться только на один блок памяти. Когда вы вызываете malloc, новая память сохраняется в arr, но старая память теряется. Вы «теряете память», потому что у машины зарезервирована старая память, но у вас нет переменной, хранящей ее адрес, поэтому у вас нет возможности найти ее снова.

Если вам нужно только сохранить последний список, вы должны освободить старую память (в arr) перед тем, как malloc'ing новый пробел. Если вам нужно сохранить все массивы, вам понадобится массив указателей в arr.

редактирование:
Вам нужно вызвать free, чтобы «освободить» ранее выделенную память, прежде чем выделять новую память. В первом наборе данных у вас нет существующего 'malloc', но всегда безопасно освободить указатель NULL, поэтому просто установите указатель на NULL в начале.

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

 int *arr=NULL;  // Mark this as pointing to no memory

  ....  

 free(arr);  // first time it does nothing, afterwards it deletes the previous reserved memory
 arr = (int*) malloc(sizeof(int) * n); // as before this reserves some memory
2 голосов
/ 15 сентября 2011

Проблемы, которые видны в вашем коде:
1. Проверка неинициализированного целого числа n в while.Чтобы это исправить, либо инициализируйте n ненулевым значением, либо используйте do{ ... } while() вместо while().
2. Вам необходимо проверить значение n, которое читается через scanf.malloc принимает тип size_t в качестве параметра unsigned int.Но n, являясь целым числом, может принимать отрицательные значения, поэтому, если введено отрицательное значение, оно будет передано как unsigned int в malloc, это может привести к нежелательным результатам (также цикл for будет выполнен неверное числораз).Вы также можете изменить тип n с integer на unsigned int type или изменить условие выхода на if( n < 1 ).
3. В вашей программе есть утечка памяти.Память, выделенная через malloc, не освобождается через free.
4. Не думайте, что malloc всегда будет успешным.Пожалуйста, проверьте успех malloc через NULL чек, т.е.

if (NULL == arr)
{
   //error handling
}

5.exit с ненулевым значением обычно указывает на аварийное завершение.Вы можете использовать break или return.break может быть лучшей идеей, так как обычно становится сложно протестировать функцию по мере увеличения точек выхода в функции (хотя это может быть и не так в вашем случае, но это к вашему сведению)
6. При желании вы можетепроверьте возвращаемое значение scanf, чтобы убедиться, что введен правильный ввод.

Помогите, это поможет!

0 голосов
/ 15 сентября 2011

Вы не инициализируете n, поэтому можете входить или не входить в цикл while. Было бы разумно начать n с -1:

int i, n = -1;

И вам следует привести возвращаемое значение malloc, которое может скрыть проблемы.

Вы также теряете память, потому что вы не вызываете free, когда вы возвращаетесь из malloc, и вы теряете отслеживание того, что читаете каждый раз, когда назначаете новое значение для arr. Брайан Роуч и Мартин Бекет упомянули эти вещи, хотя.

0 голосов
/ 15 сентября 2011

Предположительно, вы захотите получить доступ к этим массивам позже.

Как таковой, вы теряете указатель на предыдущий массив, когда вы malloc следующий (и, конечно, вызываяутечка памяти, если это было большее приложение).

Вы должны выделить чак int * (набор указателей int), а затем сохранить каждый указатель int.

Хитрость в том, что ... если вы не знаете, сколько массивов вам понадобится, вам нужно, чтобы ваш код был динамическим (например, выделите некоторое пространство, а затем выделите больше, если вызакончились).

Другой вариант заключается в том, что вы можете ограничить количество серий, которые пользователь может ввести, и сказать им, что они закончили, когда они достигнут этого.

Вот некоторая помощь, если вы хотите пойти по последнему маршруту:

int i;
int n = 1; 
int **myArrayOfArrays = malloc(sizeof(int*) * 5); /* max of 5 arrays */

int *arr;
int arrayCount = 0;
while(n != 0) {
    scanf("%d", &n);
    if(n == 0)
        break;
    else {
        if (arrayCount == 4) {
            printf("Woah there partner! That's enough!\n");
            break;
        }
        else
        {
            arr = malloc(sizeof(int) * n);
            for(i = 0; i < n; i++)
                scanf("%d", &arr[i]);
            myArrayOfArrays[arrayCount] = arr;
            arrayCount++;
         }
    } //end if
} //end while

ОДНАКО ... теперь вы не знаете, как долго каждый массив.Что является проблемой.Вы должны будете отслеживать это или использовать динамическую структуру, такую ​​как связанный список.В приведенном ниже примере мы добавляем длину в качестве первого элемента каждого массива:

int main()
{

    int i;
    int n = 1;
    int **myArrayOfArrays = malloc(sizeof(int*) * 5);

    int *arr;
    int arrayCount = 0;
    while(n != 0) {
        scanf("%d", &n);
        if(n == 0)
            break;
        else {
            if (arrayCount == 4) {
                printf("Woah there partner! That's enough!\n");
                break;
            }
            else
            {
                arr = malloc(sizeof(int) * (n + 1)); /* one more than we need */
                arr[0] = n; /* store the array length in the first element */
                for(i = 1; i <= n; i++)
                    scanf("%d", &arr[i]);
                myArrayOfArrays[arrayCount] = arr;
                arrayCount++;
             }

        } //end if
    } //end while
    int j;
    for (i = 0; i < arrayCount; i++)
    {
        int length = myArrayOfArrays[i][0]; /* retrieve the length */
        for (j = 1; j <= length; j++)
            printf("%d ", myArrayOfArrays[i][j]);
        printf("\n");
    }
}

Динамическое выделение с использованием массивов / необработанной памяти означает, что вам нужно отслеживать вещи.Лучший подход на самом деле заключается в использовании связанного списка для ваших данных.В этом случае вы могли бы иметь связанный список узлов, каждый из которых содержал список целых чисел.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...