我在理解如何char*作業時遇到問題。
在下面的例子中,struses 被 main() 呼叫。我創建了一個 buf 來存盤 const 變數,因為我想制作一個可修改的副本s1,然后我只需呼叫sortString().
這個版本對我來說很有意義,因為我知道char[]可以修改:
#include "common.h"
#include <stdbool.h>
void sortString(char string[50]);
bool struses(const char *s1, const char *s2)
{
char buf[50];
strcpy(buf, s1); // <===== input = "perpetuity";
sortString(buf);
printf("%s\n", buf); // prints "eeipprttuy"
return true;
}
void sortString(char string[50])
{
char temp;
int n = strlen(string);
for (int i = 0; i < n - 1; i )
{
for (int j = i 1; j < n; j )
{
if (string[i] > string[j])
{
temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
}
但是,在這個版本中,我故意更改了char*應該是只讀的型別。為什么我仍然得到相同的結果?
#include "common.h"
#include <stdbool.h>
void sortString(char *string);
bool struses(const char *s1, const char *s2)
{
char buf[50];
strcpy(buf, s1);
sortString(buf);
printf("%s\n", buf);
return true;
}
void sortString(char *string) // <==== changed the type
{
char temp;
int n = strlen(string);
for (int i = 0; i < n - 1; i )
{
for (int j = i 1; j < n; j )
{
if (string[i] > string[j])
{
temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
}
這就是為什么我認為它char *是只讀的。嘗試修改后出現總線錯誤read[0]:
char * read = "Hello";
read[0]='B';// <=== Bus error
printf("%s\n", read);
**更新:不知何故,編譯器確實不會拋出總線錯誤 ** 我猜是因為行為未定義,那么結果也無法預測?


uj5u.com熱心網友回復:
編譯器調整具有此函式宣告的陣列型別的引數的型別
void sortString(char string[50]);
指向元素型別的指標
void sortString(char *string);
例如,這些函式宣告是等效的,并且宣告了相同的一個函式
void sortString(char string[100]);
void sortString(char string[50]);
void sortString(char string[]);
void sortString(char *string);
在這個函式內
void sortString(char *string)
使用了buf存盤傳遞陣列副本(或通過指向它的指標傳遞的字串文字的副本)的字符陣列
char buf[50];
strcpy(buf, s1);
sortString(buf);
所以沒有問題。s1可以是指向字串文字的指標。但是字串文字的內容被復制到buf正在改變的字符陣列中
至于這個代碼片段
char * read = "Hello";
read[0]='B';
printf("%s\n", read); <=== still prints "Hello"
那么它具有未定義的行為,因為您可能無法更改字串文字。
來自 C 標準(6.4.5 字串文字)
7 未指定這些陣列是否不同,只要它們的元素具有適當的值。如果程式嘗試修改這樣的陣列,則行為未定義。
注意在 C 中,與 C 字串字面量相反的有常量字符陣列的型別。也建議在 C 中使用限定符宣告指向字串文字的指標const以避免未定義的行為,例如
const char * read = "Hello";
順便說一下,該函式sortString對傳遞的字串中的元素進行了冗余交換。最好通過以下方式宣告和定義它
// Selection sort
char * sortString( char *s )
{
for ( size_t i = 0, n = strlen( s ); i != n; i )
{
size_t min_i = i;
for ( size_t j = i 1; j != n; j )
{
if ( s[j] < s[min_i] )
{
min_i = j;
}
}
if ( i != min_i )
{
char c = s[i];
s[i] = s[min_i];
s[min_i] = c;
}
}
return s;
}
uj5u.com熱心網友回復:
char *并不意味著只讀。char *僅表示指向char.
您可能已經被告知"Hello"不能修改字串文字,例如。這并不完全正確。正確的說法是 C 標準沒有定義當您嘗試修改字串文字時會發生什么,并且 C 實作通常將字串文字放在只讀記憶體中。
我們可以用const限定符定義物件,表示我們不打算修改它們并允許編譯器將它們放在只讀記憶體中(盡管它沒有義務)。如果我們從頭開始定義 C 語言,我們將指定字串文字是const-qualified,來自字串文字的指標將是const char *.
然而,當 Cconst剛被開發出來時,沒有, 并且字串字面量產生的指標只是char *. 在const預選賽后來,這是為時已晚改變字串字面量將const因為使用舊代碼的所有的-qualified char *。
因此, a 可能char *指向不應修改的字串文字中的字符(因為未定義行為)。但char *一般來說并不意味著只讀。
uj5u.com熱心網友回復:
您認為 a 指向的區域char*不可修改的前提是錯誤的。這是完美的線路:
char s[] = "abc"; // Same as: char s[4] = { 'a', 'b', 'c', 0 };
char *p = s; // Same as: char *p = &(s[0]);
*p = 'A';
printf("%s\n", p); // Abc
演示
您出錯的原因是因為您試圖修改由字串文字創建的字串。這是未定義的行為:
char *p = "abc";
*p = 'A'; // Undefined behaviour
printf("%s\n", p);
人們通常會使用 aconst char *來表示這樣的字串。
const char *p = "abc";
*p = 'A'; // Compilation error.
printf("%s\n", p);
演示
uj5u.com熱心網友回復:
關于
char * read = "Hello";
read[0]='B';
printf("%s\n", read); // still prints "Hello"
您已經被 C 規范中的向后兼容性問題絆倒了。
字串常量是只讀的。 char *但是,是指向可修改資料的指標。字串常量的型別應該是 const char [N]其中 N 是char常量內容給出的s的數量加 1。但是,const在原始的 C 語言中(C89 之前)并不存在。因此,在 1989 年,有很多代碼曾經char *指向字串常量。因此,C 委員會將字串常量的型別設為char [N],即使它們是只讀的,以保持代碼正常作業。
通過char *指向字串常量的a 寫入會觸發未定義的行為;任何事情都可能發生。我原以為會崩潰,但寫入被丟棄也并不令人驚訝。
在 C 中,字串常量的型別實際上是,const char [N]上面的片段將無法編譯。某些 C 編譯器有一個可選模式,您可以打開該模式將字串常量的型別更改為const char [N]; 例如,GCC 和 clang 有-Wwrite-strings命令列選項。對新程式使用這種模式是個好主意。
uj5u.com熱心網友回復:
您的長示例可以簡化為您的最后一個問題。
這就是為什么我認為 char * 是只讀的,嘗試修改 read[0] 后出現總線錯誤
char * read = "Hello";
read[0]='B';
printf("%s\n", read); <=== Bus error
"Hello"是一個字串文字。嘗試修改由總線錯誤顯示的字串文字。
您的指標正在參考不應修改的記憶體。
怎么整理?您需要定義參考可修改物件的指標
char * read = (char []){"Hello"};
read[0]='B';
printf("%s\n", read);
因此,如您所見,將其宣告為可修改并不能使其可修改。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/363242.html
