![](/img/trans.png)
[英]What are the differences and similarities between global variables and heap variables in c?
[英]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
在程序中顯示為未識別的符號?
另外我想知道堆變量的生命周期和范圍是什么。
此外,我想知道,因為一個變量被保留,只有當我們返回指針被初始化內存中的空間temp
被初始化,但會發生什么temp
之后呢? 它是保持初始化還是被釋放。
我認為你混淆了兩個概念, 范圍和生命周期。
引用C11
,章節§6.2.1
對於標識符指定的每個不同實體,標識符僅在稱為其范圍的程序文本的區域內可見(即,可以使用)。 [...]
和
對象的生命周期是程序執行的一部分,在此期間保證為其保留存儲。 存在一個對象,具有一個常量地址, 33)並在其整個生命周期內保留其最后存儲的值。 [....]
這里的問題是,標識符temp
具有函數makearray()
的塊作用域。 temp
(一個指針)保存的值由內存分配器函數返回,因此很明顯它有一個liferime,直到它被解除分配,但這並不意味着temp
變量本身有一個文件范圍。
您已使用另一個變量a
來存儲makearray()
的返回值,因此請使用它。
Sourav Ghosh的答案在某些方面比這個更好。 特別是,如果您不是語言律師,可能更容易理解。 我將擴展他所撰寫的內容並提出一些(希望是建設性的)批評問題中的代碼。
C實際上沒有“全局”變量的概念。 事實上,C標准甚至沒有使用術語“變量”(至少不是通常意義上的)。 它使用“對象”這個詞,並不完全清楚哪些對象是“變量”還是“變量”。
正如Sourav的回答所說, 范圍和壽命是兩回事。 標識符的范圍是C程序文本的區域,其中該標識符是可見的; 這是一個編譯時的概念。 對象的生命周期是該對象存在的時間段; 這是一個運行時的概念。
這是您問題中的相關功能:
int * makearray(int n)
{
int *temp;
temp=(int *)malloc(sizeof(int)*n);
// printf call skipped for now
return temp;
}
temp
是int*
類型的本地指針對象。 名稱temp
僅在從聲明到結束時可見}
。 指針對象的生命周期(具有自動存儲持續時間 )是封閉塊的執行; 函數返回時指針對象不再存在。 ( 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);
}
一個更強大的程序會采取一些糾正措施(比如再次詢問),但現在終止任何錯誤都是可以的,而且比悄悄地忽略錯誤更好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.