堆变量是全局变量,什么是堆变量的范围和生命周期
are heap variables global variables and what is the scope and lifetime of heap variables
#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
在程序中显示为未识别的符号?
另外我想知道堆变量的生命周期和作用域是什么。
另外我想知道,由于一个变量在内存中保留了一个 space 只有当我们 return 指针 temp
被初始化时它被初始化但是会发生什么temp
之后呢?它是保持初始化状态还是被释放。
我认为您混淆了两个概念,scope 和生命周期。
引用 C11
,章节 §6.2.1
For each different entity that an identifier designates, the identifier is visible (i.e., can be
used) only within a region of program text called its scope. [...]
和
The lifetime of an object is the portion of program execution during which storage is
guaranteed to be reserved for it. An object exists, has a constant address,33) and retains
its last-stored value throughout its lifetime. [....]
这里的问题是,标识符 temp
具有函数 makearray()
的块作用域。 temp
(指针)持有的值由内存分配器函数 return 编辑,因此显然它在被释放之前具有生命周期,但这并不意味着 temp
变量本身具有文件范围。
您使用了另一个变量 a
来存储 makearray()
的 return 值,因此请使用它。
Sourav Ghosh's answer 在某些方面比这个更好。特别是,如果您不是语言律师,可能更容易理解。我将扩展他所写的内容,并对问题中的代码提出一些(希望是建设性的)批评。
C其实没有"global"变量的概念。事实上,C 标准甚至不使用术语 "variable"(至少不是通常意义上的)。它使用 "object" 这个词,并且不完全清楚哪些 object 是或不是 "variables"。
正如 Sourav 的正确回答所说,scope 和 lifetime 是两个不同的东西。标识符的 scope 是该标识符可见的 C 程序文本区域;这是一个 compile-time 概念。 object 的 lifetime 是 object 存在的时间段;这是一个 run-time 概念。
这是您问题中的相关函数:
int * makearray(int n)
{
int *temp;
temp=(int *)malloc(sizeof(int)*n);
// printf call skipped for now
return temp;
}
temp
是 int*
类型的局部指针 object。名称 temp
仅在声明到结束 }
期间可见。指针object(具有自动存储持续时间)的生命周期是封闭块的执行;当函数 returns 时指针 object 不复存在。 (return temp;
完全有效;它 returns 是 object 值的副本,因此 object 本身不再存在并不重要。)
malloc
函数创建一个新的 object。 object 没有自己的名字,所以它没有作用域。它的生命周期从调用 malloc
开始,一直持续到存储被调用 free
(或 realloc
,但我们可以忽略)显式释放,或者直到程序完成。
在 main
中,您有:
a=makearray(num);
readdata(temp,num);
名称 temp
是您的 makearray
函数的本地名称,因此它在 main
中不可见 - 指针 object 甚至不存在观点。但是您刚刚将值分配给 a
。你只需要改变
readdata(temp, num);
至
readdata(a, num);
现在让我们看一下代码中的其他一些问题。
#include<alloc.h>
这不是标准 header。 malloc
函数在 <stdlib.h>
.
中声明
void main()
一些编译器会接受这个,但它是 non-standard。请改用 int main(void)
。
temp=(int *)malloc(sizeof(int)*n);
不要转换 malloc
的结果。它 returns 类型 void*
的结果,可以隐式转换为您需要的任何指针类型。推荐的成语是:
temp = malloc(n * sizeof *temp);
通过使用 sizeof *temp
而不是 sizeof(int)
,您可以避免使用错误类型和悄悄分配错误大小的风险。如果您觉得可读性更好,可以写 sizeof(*temp)
而不是 sizeof *temp
;两者都有效。
并且您应该检查 malloc
调用是否成功。如果 malloc
失败,它 returns 一个空指针。您可以添加如下内容:
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);
打印指针的地址object 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
,如果成功,returns 它扫描的项目数。你应该检查一下。例如:
int count = scanf("%d",&num);
if (count != 1)
{
fprintf(stderr, "scanf failed\n");
exit(EXIT_FAILURE);
}
一个更健壮的程序会采取一些纠正措施(比如再次询问),但现在终止任何错误是可以的,而且比安静地忽略错误更好。
#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
在程序中显示为未识别的符号?
另外我想知道堆变量的生命周期和作用域是什么。
另外我想知道,由于一个变量在内存中保留了一个 space 只有当我们 return 指针 temp
被初始化时它被初始化但是会发生什么temp
之后呢?它是保持初始化状态还是被释放。
我认为您混淆了两个概念,scope 和生命周期。
引用 C11
,章节 §6.2.1
For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope. [...]
和
The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address,33) and retains its last-stored value throughout its lifetime. [....]
这里的问题是,标识符 temp
具有函数 makearray()
的块作用域。 temp
(指针)持有的值由内存分配器函数 return 编辑,因此显然它在被释放之前具有生命周期,但这并不意味着 temp
变量本身具有文件范围。
您使用了另一个变量 a
来存储 makearray()
的 return 值,因此请使用它。
Sourav Ghosh's answer 在某些方面比这个更好。特别是,如果您不是语言律师,可能更容易理解。我将扩展他所写的内容,并对问题中的代码提出一些(希望是建设性的)批评。
C其实没有"global"变量的概念。事实上,C 标准甚至不使用术语 "variable"(至少不是通常意义上的)。它使用 "object" 这个词,并且不完全清楚哪些 object 是或不是 "variables"。
正如 Sourav 的正确回答所说,scope 和 lifetime 是两个不同的东西。标识符的 scope 是该标识符可见的 C 程序文本区域;这是一个 compile-time 概念。 object 的 lifetime 是 object 存在的时间段;这是一个 run-time 概念。
这是您问题中的相关函数:
int * makearray(int n)
{
int *temp;
temp=(int *)malloc(sizeof(int)*n);
// printf call skipped for now
return temp;
}
temp
是 int*
类型的局部指针 object。名称 temp
仅在声明到结束 }
期间可见。指针object(具有自动存储持续时间)的生命周期是封闭块的执行;当函数 returns 时指针 object 不复存在。 (return temp;
完全有效;它 returns 是 object 值的副本,因此 object 本身不再存在并不重要。)
malloc
函数创建一个新的 object。 object 没有自己的名字,所以它没有作用域。它的生命周期从调用 malloc
开始,一直持续到存储被调用 free
(或 realloc
,但我们可以忽略)显式释放,或者直到程序完成。
在 main
中,您有:
a=makearray(num);
readdata(temp,num);
名称 temp
是您的 makearray
函数的本地名称,因此它在 main
中不可见 - 指针 object 甚至不存在观点。但是您刚刚将值分配给 a
。你只需要改变
readdata(temp, num);
至
readdata(a, num);
现在让我们看一下代码中的其他一些问题。
#include<alloc.h>
这不是标准 header。 malloc
函数在 <stdlib.h>
.
void main()
一些编译器会接受这个,但它是 non-standard。请改用 int main(void)
。
temp=(int *)malloc(sizeof(int)*n);
不要转换 malloc
的结果。它 returns 类型 void*
的结果,可以隐式转换为您需要的任何指针类型。推荐的成语是:
temp = malloc(n * sizeof *temp);
通过使用 sizeof *temp
而不是 sizeof(int)
,您可以避免使用错误类型和悄悄分配错误大小的风险。如果您觉得可读性更好,可以写 sizeof(*temp)
而不是 sizeof *temp
;两者都有效。
并且您应该检查 malloc
调用是否成功。如果 malloc
失败,它 returns 一个空指针。您可以添加如下内容:
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);
打印指针的地址object 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
,如果成功,returns 它扫描的项目数。你应该检查一下。例如:
int count = scanf("%d",&num);
if (count != 1)
{
fprintf(stderr, "scanf failed\n");
exit(EXIT_FAILURE);
}
一个更健壮的程序会采取一些纠正措施(比如再次询问),但现在终止任何错误是可以的,而且比安静地忽略错误更好。