2017-09-17 128 views
-1

我對C非常陌生,對於什麼時候需要手動添加字符串的終止'\ 0'字符有點困惑。給出這個函數來計算字符串長度(爲了清楚起見):爲什麼/何時爲C字符串包含終止' 0'字符?

int stringLength(char string[]) 
{ 
    int i = 0; 
    while (string[i] != '\0') { 
     i++; 
} 
    return i; 
} 

它根據空終止字符計算字符串的長度。因此,使用以下情況,'\ 0'字符的作用是什麼?

情況1:

char * stack1 = "stack"; 
printf("WORD %s\n", stack1); 
printf("Length %d\n", stringLength(stack1)); 

打印:

WORD stack 
Length 5 

情況2:

char stack2[5] = "stack"; 
printf("WORD %s\n", stack2); 
printf("Length %d\n", stringLength(stack2)); 

打印:

WORD stack��� 
Length 8 

(這些結果每次都有所不同,但從不正確)。

情況3:

char stack3[6] = "stack"; 
printf("WORD %s\n", stack3); 
printf("Length %d\n", stringLength(stack3)); 

打印:

WORD stack 
Length 5 

情況4:

char stack4[6] = "stack"; 
stack4[5] = '\0'; 
printf("WORD %s\n", stack4); 
printf("Length %d\n", stringLength(stack4)); 

打印:

WORD stack 
Length 5 

案例5:

char * stack5 = malloc(sizeof(char) * 5); 
if (stack5 != NULL) { 
    stack5[0] = 's'; 
    stack5[1] = 't'; 
    stack5[2] = 'a'; 
    stack5[3] = 'c'; 
    stack5[4] = 'k'; 
    printf("WORD %s\n", stack5); 
    printf("Length %d\n", stringLength(stack5)); 
} 
free(stack5); 

打印:

WORD stack 
Length 5 

案例6:

char * stack6 = malloc(sizeof(char) * 6); 
if (stack6 != NULL) { 
    stack6[0] = 's'; 
    stack6[1] = 't'; 
    stack6[2] = 'a'; 
    stack6[3] = 'c'; 
    stack6[4] = 'k'; 
    stack6[5] = '\0'; 
    printf("WORD %s\n", stack6); 
    printf("Length %d\n", stringLength(stack6)); 
} 
free(stack6); 

打印:

WORD stack 
Length 5 

也就是說,我想知道情況之間的差異1,2,3,4(也是爲什麼e情況2的規則行爲,並且不需要在1和3中指定空終止字符。另外,3和4的工作方式是否相同?)以及5和6如何分配相同的內容,即使分配的內存不足情況5爲空終止字符(因爲只有5個字符分配給每個字母在「鬆弛」中,它是如何檢測'\ 0'字符的,即第6個字符?)

我很抱歉這個荒謬長的問題,它只是我找不到這些具體事例還有

+1

非常廣泛的,如果你有一個字符串存儲在一個數組中,那麼你必須知道字符串結束的位置。兩個最明顯的方法是(1)保留單獨的字符數,或(2)用一些唯一字符(例如''\ 0'')終止字符串。選項2似乎是今天最常用的方法,C自動終止帶有''\ 0'的字符串常量。標準的C庫也會顯示''\ 0''終止的字符串。 –

+0

@TomKarzes:「* C自動終止字符串常量'\ 0'*」好吧,只是字符串* *文字*。 – alk

+0

不要試圖通過Trial&Error學習C,因爲這已知會導致蕭條。 – alk

回答

3

在情況1中,您正在創建一個字符串文字(一個將在只讀存儲器上的常量),該文字將隱含地添加到該字符串中\0

由於\0的位置依賴於找到字符串的結尾,所以您的stringLength()函數會打印5

在情況2中,您試圖用5個字符的字符串初始化大小爲5的字符數組,而不會爲\0分隔符留下空間。與該字符串相鄰的內存可以是任何內容,並且可能在某處存在\0。這個\0被認爲是字符串的結尾,它解釋了你得到的那些奇怪的字符。看起來,對於你輸出的結果,這個\0只有在計算字符串長度時也考慮了3個字符後才被發現。由於內存內容隨時間而改變,因此輸出可能並不總是相同的。

在情況3中,您正在使用大小爲5的字符串初始化大小爲6的字符數組,留下足夠的空間來存儲將被隱式存儲的\0。因此,它會正常工作。

案例4類似於通過

char stack4[5] = '\0'; 

來區分3.無修改完成,因爲stack4大小爲6,因此其最後指數是5,您將要覆蓋其舊值本身就是一個變量。 stack4[5]甚至在你重寫它之前就已經有了\0

在情況5中,您已經完整地填充了字符數組,並且沒有留下空間來存放\0。但是,當您打印字符串時,它會正確打印。我認爲這是因爲與malloc()分配的內存相鄰的內存恰好爲0,這是\0的值。但這是不確定的行爲,不應該依賴。真正發生的事情取決於實施。
應該注意的是,與calloc()不同,malloc()不會初始化其分配的內存。

兩個

char str[2]='\0'; 

char str[2]=0; 

是一樣的。

但是你不能依靠它爲零。由於操作系統的工作以及安全原因,動態分配的內存可能具有零作爲默認值。有關更多信息,請參閱herehere

如果您需要動態分配內存的默認值爲零,則可以使用calloc()

情況6最後有\0,其他位置有字符。打印時應顯示正確的字符串。

+3

*「在情況5 ...我認爲這是因爲malloc()分配的內存鄰近的內存爲零」* - 可以說/不可能是真的。這是因爲你已經調用了*未定義的行爲* - 如果內存中的下一個字節恰好是'0',那麼它可以工作,但是不能保證會發生什麼 - *和*'malloc'不初始化內存。但是,如果你修正了這個聲明,那麼所有的考慮,當然值得投票,會更好。 –

+1

@ DavidC.Rankin感謝您糾正我。我編輯它。 –

+1

這對我的理解非常有幫助,非常感謝你@J ... S!如果我沒有明確添加'stack6 [5] ='\ 0'這一行,情況6會發生什麼;'因爲它不是字符串文字,它會添加'\ 0'字符嗎?我認爲這不會因爲我明確添加字符。因此,如果我使用'malloc'而不是'calloc',是否會導致終止字符的未定義行爲(即依賴於以前的內存使用情況)? – Coach

4

任何地方存儲的字符串必須始終留有餘地,終止空字符的好說教的解釋。在你的一些例子中,你不這樣做,明確地給出5的長度。在這些情況下,你會得到未定義的行爲。

字符串文字總是自動獲得空終止符。儘管strlen返回長度爲5,但它確實需要6個字節。

你的情況5只工作,因爲undefined有時意味着看起來像它的工作。你可能在內存中的字符串後面有一個零值 - 但你不能依賴它。

相關問題