![](/img/trans.png)
[英]Why does dereferencing a char** value (pointer-to-pointer-to-char) differ from dereferencing a char*[] (pointer-to-char array)?
[英]In C, why can't the value of a pointer-to-char variable be changed after it has been assigned?
我不明白這種情況的區別:
#include <stdio.h>
int main()
{
int i = 0;
i = 1;
return 0;
}
這種情況:
#include <stdio.h>
int main()
{
char *mychar = "H";
*mychar = "E";
return 0;
}
這會產生編譯器警告“賦值使得沒有強制轉換的指針產生整數”。
不應該*mychar = "E"
取消引用mychar為它賦值“E”?
非常感謝。
你混淆了一些事情。
const char[]
,它存儲'E'
和'\\0'
。 它不是一個單一的角色。 對於單個字符,您使用'',如'E'
。 mychar
指向字符串文字,您無法更改字符串文字。 如果您的想法是這樣的:
char *mychar = "H";
mychar = "E";
這沒關系,你沒有改變字符串文字,只是第一次指針mychar
指向字符串文字“H”,然后指向“E”。
這你不能這樣做:
char *mychar = "Hello";
*mychar = 'E'; // Can't modify the string literal
但是你可以這樣做:
char c = 0;
char *mychar = &c;
*mychar = 'E'; // This is ok
“E”是字符串文字(char *),“E”是字符文字(char)。
請注意,您要比較的兩段代碼並不相似! 你編寫的兩段代碼(int vs char *)之間的區別會更清楚
char* mychar = "H";
*mychar = "E";
與int示例對應的類型是(char *)。 也就是說,代碼類似於“int”示例
char* mychar = "H";
mychar = "E";
字符串文字可能存儲在內存的只讀部分中。 修改字符串文字會調用未定義的行為。 你無法修改它。
添加const
限定符以讓編譯器知道字符串是不可修改的
char const *mychar = "H";
您還應該注意該聲明
*mychar = "E";
本身就是錯的。 您正在分配char *
類型char
。
我想你的意思是以下幾點
#include <stdio.h>
int main()
{
char *mychar = "H";
mychar = "E";
return 0;
}
賦值后,指針指向字符串文字"E"
。
所以你看到指針可以重新分配。 只有你應該使用正確的語法。 Expression *mychar
表示解除引用指針。 它的值不是存儲在指針中的值,而是指針指向的對象的值。
至於你的原始代碼然后在這個聲明中
*mychar = "E";
賦值的左操作數*mychar
具有char
類型,而右操作數"E"
具有指針char *
的類型(對應於字符串文字的數組類型被隱式轉換為指向其第一個元素的指針)編譯器會發出警告你正試圖做錯事。
考慮到字符串文字可能不會被更改。 所以例如這個陳述
*mychar = 'E';
有未定義的行為(這里使用整數字符常量'E'
)
char *mychar = "H"
告訴編譯器mychar
指向一個字符數組。 *mychar
取消引用數組中的第一個字符,字面意思是'H'
(注意單引號)。
當你寫:
*mychar = "E"
你試圖把一個字符串(字面意思是指向字符數組)放在文字字符應該去的地方,所以技術上正確的代碼是:
*mychar = 'E'; // assign a character-literal, not a string
請注意,雖然字符串通常是在只讀存儲器中創建的,但如果您實際上將'E'
寫入'H'
當前所在的只讀存儲器位置,則程序可能會崩潰。
如果你想避免編譯器警告( 但仍然編寫完全錯誤的代碼並崩潰 ),你會寫:
(char *)(*mychar) = "E"; // make the compiler think *mychar is pointer-to-char, very bad, will crash, but won't warn any more
這里有兩個問題 - 了解指針的類型,以及了解可以修改的內存部分。
最新版本的gcc編譯器會對該行發出警告:
char *mychar = "H";
雖然警告很難理解:
warning: deprecated conversion from string constant to ‘char*’
盡管有警告,該行代碼仍會編譯並運行。 基本上,他們不鼓勵你這樣做 - mychar現在是一個指向內存中某個位置的指針,編譯器放置了兩個字符'H'和'\\ 0'。 如果你做了類似mychar [3] ='X'的事情,那么你正在寫一個你一無所知且無法控制的記憶區域; 取決於實現,可能會導致運行時錯誤。 如果你添加const:
const char *mychar = "H";
要么
char const *mychar = "H";
警告消失了,但現在你已經明確表示你不能用這個指針來改變記憶。 如果你以后再做
*mychar = 'E';
這將導致編譯時錯誤(不是警告),因為您不能使用const char *來更改內存。
現在,關於你實際得到的錯誤信息,這是因為你寫的
*mychar = "E";
代替
*mychar = 'E';
當編譯器看到“E”時,它會在可執行文件中留出一些字符“E”和“\\ 0”的內存,“E”的值是指向內存中該點的指針(char *)。 * mychar是mychar指向的地址處的字符。 所以
*mychar = "E";
將char *指針指向“E”字符串,並將其放在mychar指向的內存中。 關於您的錯誤消息真正令人困惑的是它引用了一個整數; 我想這是因為char可以被認為是一種整數(unsigned char可以取0到255之間的任何值)。
您正在嘗試將字符的值設置為指針的值。 將指針轉換為整數是合法的(盡管很少有好主意),所以你可以試試
*mychar = (char)"E";
但是我的gcc版本(4.9.3)會產生編譯時錯誤,因為強制轉換會降低精度 - 你需要32位或64位值並將其轉換為8位值。 再次,使用我的gcc版本,
*mychar = (int)"E";
編譯(如果我沒有使mychar成為const char *),但會產生運行時錯誤,因為它試圖更改只讀內存。
也許你真正的意思是
mychar = "E";
這會將mychar從指向包含“H”的內存中的位置更改為包含“E”的內存中的位置。 這編譯並正確運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.