[英]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.