Использование динамической памяти в C - PullRequest
1 голос
/ 29 сентября 2010

Я начинающий пользователь языка Си. У меня проблема с выделением динамического массива.

Я использовал для выделения памяти вне цикла, например a=(int*)malloc(5* sizeof(int));, и все работало нормально. Теперь я хочу выделить память каждому элементу один за другим в цикле, используя malloc(), но код не работает.

Я пробовал разные варианты, такие как scanf("%d",a) &a++,scanf("%d",&a[i]); и т. Д., Но не смог. Если кто-нибудь скажет мне, что я делал неправильно, и подробно объяснит мне концепцию, я буду благодарен.

Код, с которым у меня проблемы, следующий:

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

int main()
{
  int *a;
  int i;
  system("clear");

  for(i=0;i<5; i++)
  {
    a=(int *)malloc(sizeof(int));
    printf("%u",&a);
    printf("please enter the element in array");
    scanf("%d",a[i]);
  }
  for(i=0;i<5; i++)
  {
    printf("\nthe %d entry in the array %d",i,a[i]);
  } 
  return 0;
}

Ответы [ 8 ]

6 голосов
/ 29 сентября 2010

Массив - это один "объект" (одна вещь), в котором есть место для множества элементов одного типа.

Вы ожидаете, что сможете каким-то образом распределить по одному элементу за раз, неверно, просто это не так, как работают массивы.

Вы должны сделать, как вы сначала сказали, одну malloc() комнату, выделенную для 5 элементов, а затем просто сохранить каждый из них в правильном положении в массиве внутри цикла.

Я бы рекомендовал использовать scanf("%d", &a[i]) для чтения и сохранения в массиве. Есть и другие способы написания второго аргумента, но это (на мой взгляд) самый ясный и лучший для новичка. Он читается как «адрес i-го элемента в массиве a».

1 голос
/ 29 сентября 2010

Как все уже отметили, вы действительно не хотите выделять каждый элемент массива отдельно.Однако, если, несмотря на рекомендации, вы решите, что вам нужно, вам понадобится как массив указателей, так и отдельные указатели:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
enum { ARRSIZE = 5 };

static void err_exit(const char *msg)
{
    fprintf(stderr, "%s\n", msg);
    exit(1);
}

int main()
{
  int **a;
  int i;
  a = (int **)malloc(sizeof(*a)*ARRSIZE);
  if (a == 0)
      err_exit("out of memory");

  for (i = 0; i < ARRSIZE; i++)
  {
    a[i] = (int *)malloc(sizeof(int));
    if (a[i] == 0)
        err_exit("out of memory");
    printf("%" PRIuPTR "\n", (uintptr_t)a[i]);  // Print allocated address
    printf("please enter the element in array: ");
    if (scanf("%d", a[i]) != 1)
        err_exit("failed to read a valid integer");
  }
  for (i = 0; i < ARRSIZE; i++)
  {
    printf("the %d entry in the array %d\n", i, *a[i]);
  }
  return 0;
}

Дополнительные пункты:

  • Проверьте, что malloc() сработало.
  • Использование scanf() может привести к миру боли.Вы должны проверить его статус возврата тоже.Если вы введете букву вместо цифры, ваш код будет довольно ужасным.Как правило, вам лучше использовать fgets() и sscanf().
  • Печатать новые строки в конце строк вывода - особенно в цикле печати. ​​
  • Использовать (вашу собственную) стандартизированную ошибкуфункции отчетности аналогичны err_exit();это всего лишь тривиальная версия более сложной системы функций, но наличие таких функций означает, что вы с меньшей вероятностью будете экономить на сообщениях об ошибках.
  • Используйте больше пробелов.Используйте пространство вокруг большинства операторов.Я рекомендую использовать отступ больше 2 (4 или 8).
  • Избегайте магических чисел (например, 5), если они встречаются в коде более одного раза.0 и 1 не являются магическими числами.
  • Используйте uintptr_t для печати адресов в виде целых чисел, заголовок <inttypes.h> и имена, определенные там, такие как PRIuPTR.(Обычно я печатаю адреса в шестнадцатеричном формате, но десятичное число автоматически не ошибается.) Заголовок <inttypes.h> взят из C99;это может вызвать проблемы, если ваш компилятор C достаточно ретроградный, чтобы не поддерживать C99.
  • Обратите внимание, что это , а не рекомендуемое решение для вашей проблемы с типом int;на 64-битной машине он использует намного больше памяти, чем исходное решение.
  • Однако, если вы имели дело с массивом отдельно выделенных больших структур и заранее не уверены, сколько именнонужно, тогда эта схема будет более разумной.(Вы, вероятно, не были бы привязаны к фиксированному размеру массива, хотя.)
  • Есть те, кто недоволен приведением типа возврата с malloc().Я предпочитаю это, отчасти потому, что я выучил C на машине, где приведение было решающим, и отчасти потому, что приведение обязательно в C ++, и мне нравится, когда мой код работает в подмножестве C C ++, даже когда я пишуC. (Рассматриваемый компилятор был до того, как появился стандартный C; это была машина с адресом слова; malloc() вернул char *, но битовая комбинация для char * отличалась от битовой комбинации для anything *(например, int *) по тому же адресу.)
1 голос
/ 29 сентября 2010

a[i] эквивалентно *(a+i)

scanf нужен адрес, который можно указать здесь, используя &(a[i]) или просто (a+i). Вместо этого вы передаете его a[i], что относится к данным, хранящимся в местоположении (a+i).

1 голос
/ 29 сентября 2010

В каждой итерации ваш код перезаписывает старое значение a.Таким образом, вы теряете адрес ранее выделенной памяти.

Каждый malloc выделяет только sapce для одного целого.Недопустимо разыменовывать указатель с индексом> 0. Вот почему ваш код дает неопределенное поведение.

0 голосов
/ 29 сентября 2010

Я думаю, что нашел решение вашей проблемы.Просто выполните следующие действия:

(1) Сдвиньте оператор:

a=(int *)malloc(sizeof(int));

из цикла for (поместите его непосредственно перед for) и измените его на:

a=(int *)malloc(5 * sizeof(int));

(2) Измените свой оператор scanf на:

scanf("%d",&a[i]);

Это должно сработать.

0 голосов
/ 29 сентября 2010

ответ откручивает это объяснение, но вот код для демонстрации

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

int main(){
    int *a;
    int size = 5;
    int i = 0;
    a = malloc(sizeof(int)*size);

    for(i=0;i<size;i++){
            printf("%u: ",&a);
            printf(" please enter the element in the array> ");
            scanf("%d", &a[i]);
    }

    for(i=0;i<size;i++){
            printf("index %d in the array is %d\n",i,a[i]);
    }

    free(a);

    return 0;
}
0 голосов
/ 29 сентября 2010

Все это, честно говоря, катастрофа.Если вы учитесь и совсем запутались, попробуйте прочитать по указателям C.

Посмотрите, возможно, попробуйте что-то вроде этого:

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

int main()
{
int *a;
int i;
system("clear");

a=(int *)malloc(sizeof(int)*5);

for(i=0;i<5; i++)
{
  printf("please enter the element in array");
  scanf("%d",a+i);
}

for(i=0;i<5; i++)
{
  printf("\nthe %d entry in the array %d",i,a[i]);
}

return ;
}

Или как я бы это сделал:

#include <vector.h>
#include <stdio.h>

int main()
{
  vector<int> a;
  int i;
  system("clear");

  for(i=0;i<5;i++)
  {
    printf("please enter the element in array");
    int n;
    scanf("%d",&n);
    a.push_back(n);
  }

  for(i=0;i<5; i++)
  {
    printf("\nthe %d entry in the array %d",i,a[i]);
  }

  return ;
}

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

0 голосов
/ 29 сентября 2010

Проблема в том, что вы создаете новый массив с размером = 1 каждый раз в цикле for.

Таким образом, каждый раз "a" имеет место для одного целого числа.

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