字符串數組和字符串指針
標籤:c/c++
一個例子:
char *getStr(){ char str[] = "hello world"; // 生成在棧空間的局部變量 return str; }
有問題,因爲 char str[] = "hello world";
定義了一個局部字符數組(注意str是數組),保存在棧中,初始化的字符串也在棧中,函數返回的時候,會釋放棧中被調用函數對應的空間,返回該臨時變量的地址,返回的是一個已經釋放了的空間的地址。
解決方法:str[]改成*str即可,此時,str是在棧中,但是字符串常量是在.rodata段(常量區),釋放的時候只會釋放棧中的數組名,.rodata段數據的生命週期是整個函數的執行週期。
數組名的常量特性以及二維數組的初始化方法
char a[] = "hello"; a[0] = 'H'; // success a = "world"; // error
以上這樣的代碼會報錯,因爲數組只能被初始化相當於
char *const a = "hello"
,注意a是數組名,是一個地址常量;如果重新用一個字符串常量賦值,就會改變其指向的地址。也就是說 a 指向的地址不能改變,但 a 的內容可以改變可以用a[0]=’H’來改變a數組的值;,也可以用strcpy/memcpy進行賦值,只是對不變的地址進行內容填充。常量特性在自增方面的限制:
指針可以自增(void指針除外,因爲類型未知,自增長度未知),但是數組a不能自增,常量不可以自增。下面是數組名常量特性的一個例子:
char a[3][5]; a = {"asas", "dds", "as"}; // error
【注意】是會報錯的,就是因爲“常量的原因”。所以二維數組的初始化方法:
聲明的時候初始化
聲明之後,賦值初始化,比如a[0][1] = ‘a’, 不能
a[0-3] = "asas"
,這種初始化方法使用的是字符串常量,賦值的時候會改變指針指向的地址,即會改變a的地址信息,不僅僅是二維的地址信息,還有二維下一維的地址也具有常量特性。strcpy/memcpy
等對a[0-3]進行初始化
指向字符串常量的指針的一個問題
- 版本 A
char *s = "hello";
- 版本 B
char *s; s = "hello"; // valid s[0] = 'H'; // invalid
雖然兩個版本的賦值看起來都是用字符串常量進行賦值,但是版本 A 的那個語句叫做初始化,版本 B 纔是賦值。跟A中字符串賦值不同的是:
”hello”中的雙引號做了3件事:
1.申請了空間(在常量區),存放了字符串,不像數組存在棧中
2. 在字符串尾加上了’/0’
3.返回地址
所以,s是一個指針,指針指向地址很正常。s[0] = ‘H’;出錯的原因是字符串保存在常量區!不能修改!