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

#include<stdio.h>
#include<conio.h>
#include<alloc.h>

int * makearray(int );
void readdata(int *,int );
void printdata(int *,int );

void main()
{
    int *a,num;
    clrscr();
    printf("enter the size of array\n");
    scanf("%d",&num);
    a=makearray(num);
    readdata(temp,num);
    printdata(a,num);
    getch();
}

int * makearray(int n)
{
    int *temp;
    temp=(int *)malloc(sizeof(int)*n);
    printf("address of temp is %x and value of temp is %d and first value of            temp is garbage i.e %d\n",&temp,temp,*temp);
    return temp;
}

void readdata(int *x,int n)
{
    for(n--; n>=0; n--)
    {
        printf("enter the value in cell[%d]\n",n);
        scanf("%d",x+n);
    }
    return;
}

void printdata(int *x,int n)
{
    for(n--; n>=0; n--)
        printf("the value in cell[%d] is %d",n,*(x+n));
    return;
}

в следующем коде я хочу знать, так как область видимости переменных кучи, если на время программы, почему temp отображается как неопознанный символ в программе?

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

Также я хочу знать, что, поскольку переменная зарезервирована в памяти только тогда, когда она инициализируется, когда мы возвращаем указатель temp А инициализируется, но что происходит с temp после этого? Он остается инициализированным или освобождается.

2 ответа

Я думаю, что вы смешиваете две концепции: объем и срок службы.

квотирование C11Глава §6.2.1

Для каждого отдельного объекта, который обозначает идентификатор, идентификатор является видимым (то есть может использоваться) только в пределах области текста программы, называемой ее областью действия. [...]

а также

Время жизни объекта - это часть выполнения программы, в течение которой для него гарантированно хранится память. Объект существует, имеет постоянный адрес33) и сохраняет свое последнее сохраненное значение в течение всего срока его службы. [....]

Проблема здесь в том, идентификатор temp имеет функциональность блока makearray(), Значение, удерживаемое temp (указатель) возвращается функциями выделения памяти и, таким образом, очевидно, что у него есть срок жизни, пока он не будет освобожден, но это не означает, что temp Сама переменная имеет область видимости файла.

Вы использовали другую переменную a хранить возвращаемое значение makearray()так что используйте это.

Ответ Сурава Гоша в некотором смысле лучше, чем этот. В частности, это, вероятно, легче понять, если вы не являетесь языковым юристом. Я собираюсь расширить то, что он написал, и предложить некоторую (надеюсь, конструктивную) критику кода в вопросе.

C фактически не имеет понятия "глобальные" переменные. На самом деле стандарт C даже не использует термин "переменная" (по крайней мере, не в обычном смысле). Он использует слово "объект", и не совсем понятно, какие объекты являются или не являются "переменными".

Как правильно говорит ответ Сурава, размах и продолжительность жизни - две разные вещи. Область идентификатора - это область текста программы на Си, в которой этот идентификатор виден; это концепция времени компиляции. Время жизни объекта - это период времени, в течение которого этот объект существует; это концепция времени выполнения.

Вот соответствующая функция из вашего вопроса:

int * makearray(int n)
{
    int *temp;
    temp=(int *)malloc(sizeof(int)*n);
    // printf call skipped for now
    return temp;
}

temp является локальным указателем объекта типа int*, Имя temp виден только из объявления до закрытия }, Время жизни объекта указателя (который имеет автоматическую продолжительность хранения) является выполнением включающего блока; указатель объекта перестает существовать, когда функция возвращает. (The return temp; совершенно правильно; он возвращает копию значения объекта, поэтому не имеет значения, что сам объект больше не существует.)

malloc Функция создает новый объект. Этот объект не имеет собственного имени, поэтому он не имеет области видимости. Его жизнь начинается с вызова malloc и продолжается до тех пор, пока хранилище не будет явно освобождено вызовом free (или же realloc, но мы можем игнорировать это), или пока программа не завершится.

В main, у тебя есть:

a=makearray(num);
readdata(temp,num);

Имя temp является локальным для вашего makearray функция, поэтому она не видна в main - и объект указатель даже не существует в этой точке. Но вы только что присвоили значение a, Вам просто нужно изменить

readdata(temp, num);

в

readdata(a, num);

Теперь давайте посмотрим на некоторые другие проблемы в вашем коде.

#include<alloc.h>

Это не стандартный заголовок. malloc функция объявлена ​​в <stdlib.h>,

void main()

Некоторые компиляторы примут это, но это нестандартно. использование int main(void) вместо.

temp=(int *)malloc(sizeof(int)*n);

Не бросайте результат malloc, Возвращает результат типа void*, который может быть неявно преобразован в любой тип указателя вам нужно. Рекомендуемая идиома:

temp = malloc(n * sizeof *temp);

Используя sizeof *temp скорее, чем sizeof(int) Вы избегаете риска использования неправильного типа и тихого распределения неправильного размера. Ты можешь написать sizeof(*temp) скорее, чем sizeof *temp если вы найдете его более читабельным; либо действителен.

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

if (temp == NULL)
{
    fprintf(stderr, "malloc failed\n");
    exit(EXIT_FAILURE);
}

Такое небольшое распределение вряд ли даст сбой, но вы должны выработать хорошие привычки.

printf("address of temp is %x and value of temp is %d and first value of temp is garbage i.e %d\n",&temp,temp,*temp);

Давайте разделим это на:

printf("address of temp is %x\n", &temp);

Это печатает адрес объекта указателя temp (что не особенно полезная информация, но любопытство - это хорошо). %x требует аргумент типа unsigned int, Чтобы напечатать значение указателя, используйте %p, который требует аргумент типа void*; используйте приведение, если значение указателя, которое вы печатаете, имеет другой тип:

printf("address of temp is %p\n", (void*)&temp);

Двигаемся дальше.

printf("value of temp is %p\n", (void*)temp);

Опять же, используйте %p напечатать значение указателя.

printf("first value of temp is garbage, i.e., %d\n", *temp);

Хорошо. (Строго говоря, поведение не определено, а информация бесполезна, но опять же любопытство - это хорошо.)

У вас есть пара звонков scanf, и вы предполагаете, что они успешно прочитают действительные данные. scanf, если он успешен, возвращает количество проверенных элементов. Вы должны это проверить. Например:

int count = scanf("%d",&num);
if (count != 1)
{
    fprintf(stderr, "scanf failed\n");
    exit(EXIT_FAILURE);
}

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

Другие вопросы по тегам