簡體   English   中英

堆變量是全局變量,堆變量的范圍和生命周期是什么

[英]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;
}

tempint*類型的本地指針對象。 名稱temp僅在從聲明到結束時可見} 指針對象的生命周期(具有自動存儲持續時間 )是封閉塊的執行; 函數返回時指針對象不再存在。 return temp;完全有效;它返回對象值的副本,因此對象本身不再存在並不重要。)

malloc函數創建一個新對象。 該對象沒有自己的名稱,因此它沒有范圍。 它的生命周期從調用malloc ,一直持續到通過調用free (或realloc ,但我們可以忽略它)或者直到程序完成來顯式釋放存儲。

main ,你有:

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

名稱tempmakearray函數的本地名稱,因此它在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM