![](/img/trans.png)
[英]C: struct->char *: contents changed: can someone explain this?
[英]what's difference between struct->char_member = “” and strcat(struct->char_member,“string”)?
我有以下代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct test {
char *str;
};
int main(void)
{
struct test *p = malloc(sizeof(struct test));
p->str = "hello world";
printf("%s\n",p->str);
return 0;
}
它工作正常。 但是當我寫這樣的時候:
struct test *p = malloc(sizeof(struct test));
p->str="hello";
strcat(p->str," world");
或這個:
struct test *p = malloc(sizeof(struct test));
strcat(p->str,"hello world");
我遇到了分段錯誤。
我在這里找到了一些相關的解釋:
您只為結構本身分配內存。 這包括指向char的指針,它在32位系統上只有4個字節,因為它是結構的一部分。 它不包含未知長度的字符串的內存,所以如果你想要一個字符串,你必須手動為它分配內存
有了解釋,我知道如果我想使用strcat,正確的代碼應該是這樣的:
struct test *p = malloc(sizeof(struct test));
p->str = malloc(size);
strcat(p->str,"hello world");
所以我的問題是為什么p-> str =“hello world”不需要分配內存但strcat(p-> str,“hello world”)需要在使用前分配內存?
我的編譯器是“gcc(Debian 4.9.2-10)4.9.2”。 我的英語非常基礎,請不要介意:)
需要明確的是,分配到p->str
並不需要分配。 p->str
只是一個內存地址,你可以放入任何內存地址,有效與否。 當您想要操作內存地址的內容時,需要分配。
在p->str = "hello world"
的情況下,編譯器提前保留一個內存區域並在其中放入“hello world”字符串,並使用該地址。
注意strcat
的第二個參數也是字符串文字,並且不需要分配它。
在第一個示例中,您將一個不可變字符串分配給p->str
(它存儲在只讀存儲器中)。 因此,嘗試更改內存會導致seg-fault。
在第二個示例中,您未能使用malloc
為p->str
分配空間。 由於p未初始化,因此您正在讀取您不擁有的內存中的某個隨機位置。
嘗試:
struct test *p = malloc(sizeof(struct test));
p->str=(char *)malloc(12 * sizeof(char));
strcpy(p->str, "hello");
strcat(p->str," world");
這里我們有malloc
足夠的空間用於“hello world”(加上'\\ 0'字符)。 strcpy
將字符串“hello”復制到已分配的內存中的位置。 現在strcat
成功了,因為你“擁有”p-> str指向的內存。
另外不要忘記你有malloc的free()
內存!
編輯:作為旁注,我認為你可能會對為結構分配內存感到困惑。 在這種情況下,為struct分配內存只能為char *
提供足夠的內存; 但是你沒有為指向的實際指針分配內存。
實際上沒有必要為struct test
分配內存,只能為char *
分配內存。 更好的是:
struct test p;
p.str=(char *)malloc(12 * sizeof(char));
strcpy(p.str, "hello");
strcat(p.str," world");
"hello, world"
, "hello"
和" world"
都是字符串文字 ; 它們都存儲為char
數組,以便程序一啟動就可以使用,並且在程序的生命周期內可見。
該聲明
p->str = "hello, world";
將字符串文字的地址復制到p->str
。 這適用於printf
語句以及只需要讀取字符串的任何其他內容。 但是,在聲明中
p->str = "hello";
strcat( p->str, " world" );
您試圖通過將字符串" world"
附加到它來修改字符串文字"hello"
。 字符串文字是不可修改的,並且嘗試這樣做會導致未定義的行為 ,在您的情況下是段錯誤 - 在許多流行的桌面平台上,字符串文字保存在內存的只讀部分。
因此,您需要留出可以寫入的內存區域。 您可以使用動態執行此操作
p->str = malloc( SOME_SIZE); // enough space to store your final string
strcpy( p->str, "hello" ); // copy the contents of "hello" to the memory str points to
strcat( p->str, " world" ); // append the contents of " world" to the memory str points to
或者你可以設置p->str
指向你在別處聲明的數組
char buffer[SOME_SIZE];
p->str = buffer; // assigns the *address* of buffer to p->str
或者您可以在struct
定義中將str
聲明為char 數組 :
struct test
{
char str[SOME_SIZE];
};
其中SOME_SIZE
足以容納您想要存儲的任何字符串。 請注意,在這種情況下, p->str = "hello"
將不起作用; 你不能使用=
運算符來相互分配數組的內容; 在這種情況下你必須使用strcpy
。
顯然,使用malloc
或calloc
動態分配更加靈活; 您可以根據需要分配盡可能多的內存,並且可以根據需要使用realloc
增大或縮小動態緩沖區您只需要記住在完成后釋放p->str
。
您仍然可以將字符串文字的地址分配給p->str
,只需要知道您不能將該地址傳遞給strcpy
或strcat
或strtok
等函數或任何其他嘗試修改輸入字符串內容的函數。
你是對的。 但是你應該在這里使用strcpy
而不是strcat
,因為strcat
會將一個字符串附加到p->str
,這是未初始化的。
事實上p->str = "hello world";
將使p->str
指向(匿名)字符串litteral。 它的存儲器通常在程序執行開始時自動分配。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.