簡體   English   中英

char a [] =?string?有什么區別?和char * p =?string?;?

[英]What is the difference between char a[] = ?string?; and char *p = ?string?;?

正如標題所說,有什么區別

char a[] = ?string?; and 
char *p = ?string?;  

這個問題在接受我采訪時被問到了。 我甚至不理解這個說法。

char a[] = ?string?

這是什么? 運營商? 它是字符串的一部分還是具有某些特定含義?

? 似乎是一個錯字,它在語義上是無效的。 所以答案假定為? 這是一個錯字,並解釋了面試官實際上可能要問的問題。


一開始,兩者都截然不同:

  1. 第一個創建一個指針。
  2. 第二個創建一個數組。

繼續閱讀以獲得更詳細的解釋:

陣列版本:

char a[] = "string";  

創建一個足以容納字符串文字“string”的數組,包括其NULL終止符。 使用字符串文字“string”初始化數組string 可以在以后修改該陣列 此外,即使在編譯時也可以知道數組的大小,因此可以使用sizeof運算符來確定其大小。


指針版本:

char *p  = "string"; 

創建指向字符串文字“string”的指針。 這比數組版本快, 但指針指向的字符串不應更改 ,因為它位於只讀實現定義的內存中。 修改此類字符串文字會導致未定義的行為

事實上,C ++ 03不贊成[Ref 1]使用不帶const關鍵字的字符串文字。 聲明應該是:

const char *p = "string";

此外,您需要使用strlen()函數,而不是sizeof來查找字符串的大小,因為sizeof運算符只會為您提供指針變量的大小。


哪個版本更好,我應該使用哪個版本?

取決於用法。

  • 如果您不需要對字符串進行任何更改,請使用指針版本。
  • 如果要更改數據,請使用陣列版本。

注意:這不是C ++,但這是C特定的。

請注意,使用不帶const關鍵字的字符串文字在C中完全有效。但是,修改字符串文字仍然是C [參考文獻2]中的未定義行為。

這提出了一個有趣的問題,
當在C中使用字符串文字時,char *和const char *之間有什么區別?


對於Standerdese粉絲:
[參考1] C ++ 03標准:§4.2/ 2

不是寬字符串文字的字符串文字(2.13.4)可以轉換為“指向字符的指針”的右值; 可以將寬字符串文字轉換為“指向wchar_t的指針”類型的右值。 在任何一種情況下,結果都是指向數組第一個元素的指針。 僅當存在明確的適當指針目標類型時才考慮此轉換,而不是在通常需要從左值轉換為右值時。 [ 注意:此轉換已棄用 見附錄D.]為了在重載決策(13.3.3.1.1)中進行排序,這種轉換被認為是一個數組到指針的轉換,然后是一個限定轉換(4.4)。 [示例:“abc”轉換為“指向const char的指針”作為數組到指針的轉換,然后轉換為“指向char的指針”作為限定轉換。 ]

C ++ 11簡單地刪除了上面的引用,這意味着它是C ++ 11中的非法代碼。

[參考2] C99標准6.4.5 / 5“字符串文字 - 語義”:

在轉換階段7中,將值為零的字節或代碼附加到由字符串文字或文字產生的每個多字節字符序列。 然后使用多字節字符序列初始化靜態存儲持續時間和長度的數組,該數組足以包含序列。 對於字符串文字,數組元素的類型為char,並使用多字節字符序列的各個字節進行初始化; 對於寬字符串文字,數組元素的類型為wchar_t,並使用寬字符序列進行初始化...

如果這些數組的元素具有適當的值,則這些數組是否不同是未指定的。 如果程序試圖修改此類數組,則行為未定義。

第一個是數組,另一個是指針。

數組聲明char a[6]; 請求留出六個字符的空格,以名稱a 也就是說,有一個名為a的位置,可以坐6個字符。 指針聲明char *p; 另一方面,請求一個持有指針的地方。 指針將由名稱p知道,並且可以指向任何位置的任何char(或連續的chars數組)。

聲明

  char a[] = "string"; char *p = "string"; 

會導致數據結構可以表示如下:

  +---+---+---+---+---+---+----+ a: | s | t | r | i | n | g | \\0 | +---+---+---+---+---+---+----+ +-----+ +---+---+---+---+---+---+---+ p: | *======> | s | t | r | i | n | g |\\0 | +-----+ +---+---+---+---+---+---+---+ 

重要的是要意識到像x[3]這樣的引用根據x是數組還是指針生成不同的代碼。 鑒於上面的聲明,當編譯器看到表達式a[3] ,它會發出代碼從位置a開始,移動三個元素,然后在那里獲取字符。 當它看到表達式p[3] ,它會發出代碼從位置p開始,在那里獲取指針值,向指針添加三個元素大小,最后獲取指向的字符。 在上面的例子中, a[3]p[3]碰巧都是字符l ,但編譯器以不同的方式得到它們。

資料來源: comp.lang.c常見問題清單·問題6.2

char a[] = "string";

這會在堆棧上分配字符串。

char *p = "string";

這會在堆棧上創建一個指針,指向進程數據段中的文字。

? 是誰寫的不知道他們在做什么。

堆棧,堆,數據段(和BSS)和文本分段是進程內存的四個部分。 定義的所有局部變量都將在堆棧中。 使用malloccalloc以動態方式分配的內存將在堆中。 所有全局變量和靜態變量都將在數據段中。 文本段將包含程序的匯編代碼和一些常量。

在這4個段中,文本段是READ ONLY段,而所有其他三個段用於READWRITE

char a[] = "string"; - 這個statemnt將在堆棧中為7個字節分配內存(因為局部變量),並且它將保留所有6個字符( s, t, r, i, n, g )加上NULL字符( \\0 )。

char *p = "string"; - 這個語句將在堆棧中為4個字節(如果它是32位機器)分配內存(因為這也是一個局部變量)並且它將保存常量字符串的指針,其值為"string" 這個6字節的常量字符串將在文本段中。 這是一個恆定值。 指針變量p只指向該字符串。

現在a[0] (索引可以是0到5)表示,它將訪問堆棧中該字符串的第一個字符。 所以我們也可以在這個位置寫作。 a[0] = 'x' 允許此操作,因為我們在堆棧中具有READ WRITE訪問權限。

但是p[0] = 'x'會導致崩潰,因為我們只有READ訪問文本段。 如果我們對文本段進行任何寫操作,將發生分段錯誤。

但是你可以改變變量p的值,因為它的局部變量在棧中。 如下

char *p = "string";
printf("%s", p);
p = "start";
printf("%s", p);

這是允許的。 這里我們將存儲在指針變量p中的地址更改為字符串start地址(同樣start也是文本段中的只讀數據)。 如果要修改*p值,請選擇動態分配的內存。

char *p = NULL;
p = malloc(sizeof(char)*7);
strcpy(p, "string");

現在允許p[0] = 'x'操作,因為現在我們正在寫入堆。

char *p = "string"; 創建一個指向只讀內存的指針,其中存儲了字符串文字"string" 試圖修改p指向的字符串導致未定義的行為。

char a[] = "string"; 創建一個數組並使用字符串文字"string"初始化其內容。

它們在存儲內存的位置上有所不同。 理想情況下,第二個應該使用const char *。

第一個

char buf[] = "hello";

創建一個足夠大的自動緩沖區來保存字符並將它們復制(包括空終止符)。

第二個

const char * buf = "hello";

應該使用const並簡單地創建一個指向內存的指針,該指針通常存儲在靜態空間中,修改它是非法的。

相反(你可以安全地修改第一個而不是第二個)的事實是從函數返回第二個指針是安全的,而不是第一個。 這是因為第二個將保留在函數范圍之外的有效內存指針,第一個不會。

const char * sayHello()
{
     const char * buf = "hello";
     return buf; // valid
}

const char * sayHelloBroken()
{
     char buf[] = "hello";
     return buf; // invalid
}

a聲明一個char值數組 - 一個終止的char數組。

p聲明一個指針,指向一個不可變的,終止的C字符串,其確切的存儲位置是實現定義的。 請注意,這應該是const -qualified(例如const char *p = "string"; )。

如果你用std::cout << "a: " << sizeof(a) << "\\np: " << sizeof(p) << std::endl;打印出來的話std::cout << "a: " << sizeof(a) << "\\np: " << sizeof(p) << std::endl; ,您將看到它們的大小差異(注意:值可能因系統而異):

a: 7
p: 8

這是什么? 運營商? 它是字符串的一部分還是具有某些特定含義?

 char a[] = ?string? 

我假設它們曾經是雙引號"string" ,它可能被轉換為“智能引號”,然后在此過程中無法表示,並被轉換為?

C和C ++具有非常相似的Pointer to Array關系......

我不能說出你要問的兩個語句的確切內存位置,但我發現它們有趣且有用,可以理解char Pointer聲明和char數組聲明之間的一些區別。

為清楚起見:

C指針和數組關系

C ++指向數組的指針

我認為記住C和C ++中的數組是指向數組第一個元素的常量指針重要的。 因此,您可以對陣列執行指針運算。

char * p =“string”; <---這是一個指向字符串第一個地址的指針。

以下也是可能的:

char *p;
char a[] = "string";

p = a; 

此時p現在引用a的第一個內存地址(第一個元素的地址)

所以* p =='s'

*(p ++)=='t'等等。 (或*(p + 1)=='t')

同樣的事情適用於:*(a ++)或*(a + 1)也等於't'

暫無
暫無

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

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