簡體   English   中英

堆棧數組 C++ 的Strcpy行為

[英]Strcpy behavior with stack array c++

這是我的程序:

#include <cstring>
const int SIZE =10; 

int main() 
{ 
    char aName [SIZE]; // creates an array on the stack
    std::strcpy(aName, "Mary");
    return 0;
}

這個程序顯然沒用,我只是想了解 strcpy 函數的行為。

這是它的簽名: char * strcpy ( char * destination, const char * source )

所以當我這樣做時: std::strcpy(aName, "Mary");

我通過值傳遞變量 aName。 我知道 aName (在 main 中)包含數組的地址。 那么這個斷言是否正確:strcpy 創建了一個名為 destination 的局部變量,該變量的值是我在 main 函數的堆棧上創建的數組 aName 的地址?

我問這個是因為它讓我很困惑。 每當我遇到地址時,它通常是指向在堆上分配的內存......

謝謝!

每當您遇到地址時,並不意味着它總是指向分配給堆的內存。

您可以像這樣將變量的地址分配給指針

int a=5;
int *myPtr= &a;

現在, myPtr是整數類型的一個指針,它指向其上堆疊產生變量的存儲器,其是a具有值5。

因此,每當您創建一個指針並使用new關鍵字分配內存(地址)時,它都會在heap上分配內存。 所以,如果我分配這樣的值,它將在堆棧中

int *myPtr= new int[5];

那么這個斷言是否正確:strcpy 創建了一個名為 destination 的局部變量,該變量的值是我在 main 函數的堆棧上創建的數組 aName 的地址?

是的。

每當我遇到地址時,它通常是指向在堆上分配的內存......

是的,通常。 但不總是。

指向非動態分配對象的指針在 C++ 中相當少見,盡管在 C 中它更常見,因為這是具有“輸出參數”的唯一方法(C 沒有引用)。

strcpy是 C 標准庫中的一個函數。

函數參數是它的局部變量。

在這次通話中

std::strcpy(aName, "Mary");

這兩個數組(一個在 main 中創建並具有自動存儲持續時間,另一個是具有靜態存儲持續時間的字符串文字)被隱式轉換為指向它們的第一個元素的指針。

所以你可以想象這個調用和函數定義如下

std::strcpy(aName, "Mary");

 // …

char * strcpy ( /* char * destination, const char * source */ )
{
    char *destination = aName;
    const char *source = "Mary";

    // …

    return destination;
}

甚至喜歡

char *p_to_aName = &aName[0];
const char *p_to_literal = &"Mary"[0];
std::strcpy( p_to_aName, p_to_literal );

 // …

char * strcpy ( /* char * destination, const char * source */ )
{
    char *destination = p_to_aName;
    const char *source = p_to_literal;

    // …

    return destination;
}

即在函數內,它的參數是指針類型的局部變量,具有自動存儲持續時間,由指向傳遞的字符數組的第一個字符的指針初始化

也許看一下strcpy()的示例實現會有所幫助:

char* strcpy(char* d, const char* s)
{
    char* tmp = d;

    while (*tmp++ = *s++)
        ;

    return d;
}

這就是它的全部內容。 將字符從源復制到目標,直到源字符為空(包括空)。 將指針返回到目的地的開頭。 完畢。

指針指向內存。 該內存是“堆棧”、“堆”還是“靜態”並不重要。

那么這個斷言是否正確:strcpy 創建了一個名為 destination 的局部變量,該變量的值是我在 main 函數的堆棧上創建的數組 aName 的地址?

是的。 那是正確的。 雖然我可能不會稱它為局部變量。 它是一個參數。 局部變量通常是這樣的:

int localVariable;

“參數”一詞通常與以下內容相關聯:

int myFunction(int parameter) {
    // use parameter some where...
}

不過,要點大致相同:它創建了一個變量,一旦函數退出,該變量就會超出范圍。

我問這個是因為它讓我很困惑。 每當我遇到地址時,它通常是指向在堆上分配的內存......

是的,這是他們最常見的用例。 但這不是他們唯一的用途。 指針是地址,每個變量在內存中都有一個地址,無論它是分配在“堆”還是“堆棧”上。

在這里使用可能是因為指向char指針通常用於存儲字符串,尤其是在較舊的編譯器上。 結合數組“衰減”為指針的事實,使用指針可能更容易。 這樣做當然也更向后兼容。

該函數可以同樣輕松地使用數組,如下所示:

char * strcpy ( char destination[], const char source[ )

但我將假設在這里使用指針更容易(注意:我認為你不能在 C++ 中返回一個數組,所以我仍然使用char * 。但是,即使你可以,我也會想象一下,無論如何使用指針仍然更容易,所以我認為它在這里沒有太大區別。)。


指針的另一個常見用途是將它們用作“按引用傳遞”的一種方式:

void foo(int * myX) {
    *myX = 4;
}

int main() {
    int x = 0;

    foo(&x);

    std::cout << x; // prints "4"

    return 0;
}

然而,在現代 C++ 中,實際上通過引用傳遞比這個更受歡迎:

void foo(int & myX) {
    myX = 4;
}

int main() {
    int x = 0;

    foo(x);

    std::cout << x; // prints "4"

    return 0;
}

但我把它作為另一個例子來幫助說明這一點:在堆上分配的內存並不是指針的唯一用途,而是最常見的用途(盡管實際上動態分配的內存在現代 C++ 中已經被諸如std::vector ,但這不是重點)。

我知道 aName (在 main 中)包含數組的地址。

你知道錯了。 aName是一個數組。 它包含元素,而不是地址。

但是當你使用數組的名稱作為值時,比如將它傳遞給 strcpy 時,它會被隱式轉換為指向數組第一個元素的指針(指針的值是指向對象的內存地址)。 這種隱式轉換稱為衰減

那么這個斷言是否正確:strcpy 創建了一個名為 destination 的局部變量,該變量的值是我在 main 函數的堆棧上創建的數組 aName 的地址?

這是足夠正確的。 澄清:它是一個函數參數,而不是一個局部變量。 但這里的區別並不重要。 從技術上講,是調用者負責將參數壓入堆棧或將它們存儲到寄存器中,因此可以認為main “創建”了變量。

每當我遇到地址時,通常都是指向在堆上分配的內存

指針不是與“堆”唯一關聯的。 幾乎可以指向任何對象,無論它具有動態、靜態或自動存儲,甚至是子對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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