c-язык динамической памяти - PullRequest
1 голос
/ 04 октября 2010

Привет всем спасибо за поддержку, но никто не предоставил мне необходимую информацию, сейчас я пытаюсь сделать эту программу, как эта

#include<stdio.h>
#include <stdlib.h>
int main()
{
    int **a,i,j;
    system("clear");

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

    for (i=0; i<5; i++)
    {
        a[i]= malloc(sizeof(int)*3);

        for (j=0; j<3; j++)
        {
            printf("\nplease enter the [%d][%d] location = ",i,j);
            scanf("%d",&a[i][j]);
        }
    }


    for (i=0; i<5; i++)
    {
        for (j=0; j<3; j++)
        {
            printf("\nthe value enter  enter the [%d][%d] location = ",i,j);
            printf("%d",a[i][j]);
        }
    }
    free(a);
    return ;
}

я собрал его при компиляции, он показывает предупреждение, следующее за

c:8: warning: assignment from incompatible pointer type

при запуске программы пользователь получает 15 значений, но не показывает введенное пользователем значение Кто-нибудь может объяснить, что я делаю неправильно, может ли кто-нибудь объяснить мне концепцию двойного указателя и динамического распределения памяти

Ответы [ 5 ]

5 голосов
/ 04 октября 2010

Во-первых, неправильное распределение памяти в вашем коде.Первый malloc должен выглядеть следующим образом

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

Ваш a равен int **, как вы его заявили.Вы применяете результат malloc к int *.int * и int ** - это несовместимые типы, о которых вас предупреждает компилятор.Чтобы избежать таких ошибок в будущем, избавьтесь от вредной привычки использования типов в выражениях.Типы в C принадлежат объявлениям . Заявления должны быть максимально независимыми от типа.Вышеупомянутый malloc вызов будет выглядеть намного лучше

a = malloc(5 * sizeof *a);

Примечание: без приведения, не упоминаются типы.Второй malloc будет выглядеть следующим образом

a[i] = malloc(3 * sizeof *a[i]);

Надеюсь, вы видите шаблон, в соответствии с которым построены эти malloc вызовы.

Вы также забыли освободить память для отдельныхподмассивы в вашей программе (a[i] память никогда не освобождается, в то время как a память есть).

Что касается программы, не показывающей введенные значения ... Первая проблема со сломанным вызовом mallocдостаточно серьезна, чтобы помешать работе вашей программы, но может показаться, что она работает на некоторых платформах.На таких платформах он должен показывать значения.Вы уверены, что не просто пропустили вывод?

3 голосов
/ 04 октября 2010

В этом коде есть несколько ошибок. Прежде всего, предупреждение относится к тому факту, что вы пытаетесь присвоить указатель на целое число (int *) переменной (a), которая является указателем на указатель на целое число (int **), которое вы на самом деле хотите использовать в качестве массива массивов.

Итак, первая коррекция, в строке 8 это не

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

но это

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

(это приведение в C не является строго необходимым, но, будучи программистом на C ++, я предпочитаю так держать)

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

Затем, в конце приложения, вы free используете только пространство, выделенное первым malloc, в то время как вы сделали другие пять выделений (по одному для каждой строки). Таким образом, вы можете выполнить освобождение в последнем цикле, сразу после отображения каждой строки.

for (i=0; i<5; i++)
{
    for (j=0; j<3; j++)
    {
        printf("\nthe value enter  enter the [%d][%d] location = ",i,j);
        printf("%d",a[i][j]);
    }
    free(a[i]);
    a[i]=NULL;
}
free(a);
a=NULL;

Помните: для каждого malloc или calloc вы должны иметь соответствующий free, иначе вы теряете память.

Здесь, после каждого освобождения, я устанавливал соответствующий указатель на NULL, чтобы отбросить те старые, теперь недействительные, указатели. Кто-то говорит, что такое поведение может маскировать двойные освобождения (поскольку free(NULL) не вызывает ошибок), но ИМХО это лучше, чем альтернатива

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

Кстати, system("clear"); безобразно. Вы должны использовать платформо-зависимый способ очистки экрана, даже лучше, если он включен в функцию; в Linux с обычными (X3.64) терминальными эмуляторами что-то вроде этого может быть в порядке:

void ClearScreen()
{
    fputs("\x1B[2J\x1B[1;1H", stdout);
    fflush(stdout);
}
1 голос
/ 04 октября 2010
   a = (int*)malloc(sizeof(int)*5);
     ^
     |
Warning due to this

a - указатель на указатель на int т.е. int **.

Вы приводите возвращаемое значение malloc() к int*, а затем присваиваете его int**, чтобы неявное преобразование из int* в int** генерировало предупреждение. Более того, он должен быть sizeof(int *) внутри первого malloc() [поскольку вы пытаетесь выделить память для двумерного массива].

Попробуйте это:

a=(int**)malloc(sizeof(int*)*5);
1 голос
/ 04 октября 2010

a указывает на массив int указателей.Таким образом, каждый элемент этого массива имеет тип int*, а не int.Таким образом, вы должны использовать sizeof(int*).

это

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

должно быть

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

Поскольку malloc в C возвращает void Указатель и C неявно приводят от и к void*, нет необходимости в приведении.

Возможно, вы захотите прочитать это:

Должен ли я явно приводить mallocВозвращаемое значение ()?

0 голосов
/ 04 октября 2010

В строке 6 вы должны иметь

a = (int**) malloc(sizeof(int*) * 5)); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...