簡體   English   中英

為什么以下代碼片段分配會產生令人困惑的輸出?

[英]Why following code snippets assignment gives confusing output?

我正在學習 C。我遇到了字符串數組。 我對以下代碼有些困惑。 我期待一種輸出; 但是,由於讀取訪問沖突而獲得完全不同類型的輸出或程序崩潰。

我在 Visual Studio 2017 上運行了這段代碼,帶有 _CRT_SECURE_NO_WARNINGS

// case 1

char* name[2];
//name[0] = (char*)malloc(sizeof(char*) * 10); 
//name[1] = (char*)malloc(sizeof(char*) * 10);
name[0] = "john";
name[1] = 'doe';
printf("%s\n", name[0]); // prints john
//printf("%s\n", name[1]); // gives read access violation exception, why??? even with dynamically allocated memory

// case 2

char* name2[2] = { "emma", "olsson" };
printf("%s\n", name2[0]); // prints emma
printf("%s\n", name2[1]); // prints olsson, why no error???

// case 3

for (int i = 0; i < 2; i++)
{
    name[i] = name2[i];
}
printf("%s\n", name[0]); // prints emma
printf("%s\n", name[1]); // prints olsson, why no error??? 

// case 4

char inputName[10];
int i = 0; 
while (i < 2)
{
fgets(inputName, sizeof(inputName), stdin); // first input: Max   second input: Payne
char* pos = strchr(inputName, '\n');
if (pos != NULL)
    *pos = '\0';
name[i++] = inputName;
}
printf("%s\n", name[0]); // prints Payne, why not Max???
printf("%s\n", name[1]); // prints Payne

對於情況 1, 'doe' 不是字符串。

情況 2 有效,因為您正在使用字符串文字初始化指針。

第 3 種情況也有效,因為您將第 2 種情況下的相同初始化指針分配給第 1 種情況的指針。 您的名稱數組指針基本上設置為指向 name2 指針指向的位置。

在情況 4 中,您聲明 inputName 指向一組 10 個字符。 然后每次你得到一個新的輸入時,你都會把它寫到同一個內存部分。 通過這樣做: name[i++] = inputName; 您並沒有像您想象的那樣將新的字符數組復制到 name[i]。 相反,您告訴 name[i] 字符指針指向 inputName。 所以 name 打印最后一次輸入兩次是正常的,因為這是 inputName 指向的,以及兩個 name 字符指針。

目前尚不清楚 OP 的代碼是在 main() 內運行還是在用戶定義的函數中運行以及返回什么樣的值。 也就是說,在刪除多余的變量重新聲明后,這是我實現工作代碼的方式:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {

char * name[2];
char * name2[2]={ "emma", "olsson" };
char inputName[10];
char names[BUFSIZ];
int i = 0; 

// case 1
name[0] = "john";
name[1] = "doe";
printf("%s %s\n", name[0],name[1]); //john doe

// case 2
printf("%s %s\n", name2[0],name2[1]);//emma olsson

// case 3
for (i = 0; i < 2; i++){
    name[i] = name2[i];
}
printf("%s %s\n", name[0],name[1]);//emma olsson

// case 4
i=0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
    strcat(names,inputName);
    i++;
}
printf("\n%s\n",names);
return 0;
}

在此處查看實時代碼

OP 應該用雙引號替換doe周圍的單引號,雙引號表示以空字符結尾的字符串。 單引號表示單個字符,即 'a' 表示一個字節值,而“a”表示包含兩個字符的字符串,一個 'a' 和一個 '\\0'。

此外,OP 應包括其他兩個庫以促進執行。 特別是,內建字符串函數需要 string.h 才能正確執行。

案例 2 和案例 3 有效,因為字符串包含在雙引號中而不是單引號中。 請注意,在每種情況下,printf() 的“%s”格式說明符都表示需要顯示一個字符串。

在最后一種情況下,fgets() 相對於標准輸入,成功后將用戶輸入作為字符串返回。 但是該輸入將在 while 循環中被覆蓋,除非在每次迭代中將舊輸入與新輸入連接起來。 否則,當 inputName 元素值由於其地址保持不變而發生變化時,只會顯示最新的輸入字符串。 下面是一些說明這一點的代碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
char * name[2];
char inputName[10];
int i = 0; 

while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
    printf("inputName: %p points to: %s",inputName,inputName);
    name[i++] = inputName;

}
printf("\n  name[0]: %p points to: %s\n  name[1]: %p points to: %s",name[0],name[0],name[1],name[1]);
return 0;
}
Output:

 inputName: 0x7fff8a511a50 points to: Maxine
 inputName: 0x7fff8a511a50 points to: Pauline
   name[0]: 0x7fff8a511a50 points to: Pauline  
   name[1]: 0x7fff8a511a50 points to: Pauline

查看實時代碼。

順便說一句,您不需要數組來顯示名稱,實際上只要在循環內代碼連接用戶輸入,就可以在循環外顯示名稱。

暫無
暫無

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

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