字符串賦值給字符指針(char *a="hello")的正確理解方式


對於語句  char *a="hello";

對於這個聲明方式,會造成的誤解是:聲明了一個字符指針(它會指向一個位置),將“字符串”賦值給 指針表達式"*a"所指向的地址。但正解是:聲明了一個字符指針后,並用字符串常量的第一個字符的地址賦值給指針變量a。
即正確順序是:

  • 1.分配內存給字符指針;
  • 2.分配內存給字符串;
  • 3.將字符串首地址賦值給字符指針;

這里有兩點需要考慮清楚的地方:

*a只是指向一個字符。舉例如下:

#include <iostream> #include <string>
using namespace std; int main() { char *a ="abcdefg"; cout << "輸出字符: " << *a << endl; cout << "第二次輸出字符: " << *(a+1) << endl; cout << "輸出字符串: " << a << endl; return 0; }

結果如下

輸出字符: a
第二次輸出字符: b
輸出字符串: abcdefg

 若字符串常量出現在在表達式中,代表的值為該字符串常量的第一個字符的地址。所以”hello”僅僅代表的是其地址。 
原聲明方式相當於以下聲明方式:

char *a; a="hello";/*這里字符串"hello"僅僅代表其第一個字符的地址*/  

 

1.但還是不明白為什么字符串可以賦值給字符指針變量

 

char *p,a='5'; p=&a;                     //顯然是正確的,
p="abcd";              //但為什么也可以這樣賦值??

雙引號做了3件事:  
1.申請了空間(在常量區),存放了字符串 
2. 在字符串尾加上了'/0'    
3.返回地址
返回的地址,賦值給了指針變量p    

2.以char *p = “hello”為例,把p換成數組,然后再賦值就不行了

字符串常量"hello"出現在一個表達式中時,"hello"表達式使用的值就是這些字符所存儲的地址(在常量區),而不是這些字符本身。

所以,可以把字符串賦值給指向字符的指針p,而不能把字符串賦值給一個字符數組。

char a[10] = “hello”; //這樣可以,這種情況是c語言初始化所支持的

如果寫成char a[10]

然后 a = “hello” 這樣就錯誤了。

因為同樣是a數組,char a[10] = “hello”;這種是數組的初始化,和a[0] = ‘h’ a[1] = ‘e’…是一個道理

但是換成char a [10],然后a = “hello”是不行的,“hello”賦值的值是一個地址,而a雖然也有地址,與指針不同,指針的值是地址,而數組的值雖然同為地址,卻是一個常量,不能給常量賦值

代碼測試

#include <iostream> #include <string>

using namespace std; int main() { char *p = "hello"; cout << p << endl; char a[10]; a = "hello"; return 0; }

報錯 error C3863: array type 'char [10]' is not assignable

而修改后,正常運行

#include <iostream> #include <string>

using namespace std; int main() { char *p = "hello"; cout << p << endl; char a[10] = "hello"; //數組初始化
    return 0; }

 

 

字符數組,字符指針,字符串常量 知識回顧

1.以字符串形式出現的,編譯器都會為該字符串自動添加一個0作為結束符,如在代碼中寫 "abc",那么編譯器幫你存儲的是"abc\0"

2."abc"是常量嗎?
1.當作為字符數組初始值的時候,"abc"不是常量

char str[] = "abc";

因為定義的是一個字符數組,所以就相當於定義了一些空間來存放"abc",而又因為字符數組就是把字符一個一個地存放的,所以編譯器把這個語句解析為

char str[4] = {'a','b','c','\0'};

2.當賦值給 字符指針變量的時候:如char* ptr = "abc" 此時是常量

char* ptr = "abc" //規范不允許這種c的寫法

規范寫法

const char* ptr = "abc";

因為定義的是一個普通字符指針,並沒有定義空間來存放"abc",所以編譯器得幫我們 找地方來放"abc",顯然,把這里的"abc"當成常量並把它放到程序的常量區是編譯器 最合適的選擇。簡言之,如果char* ptr = "abc";寫在函數體內,那么雖然這里的"abc\0"被 放在常量區中,但是ptr本身只是一個普通的指針變量,所以ptr(指針)是被放在上的, 只不過是它所指向的東西(值)被放在常量區罷了

3.數組的類型是由該數組所存放的東西的類型以及數組本身的大小決定的

如char s1[3]和char s2[4],s1的類型就是char[3],s2的類型就是char[4], 也就是說盡管s1和s2都是字符數組,但兩者的類型卻是不同的

4.字符串常量的類型可以理解為相應字符常量數組的類型

如"abcdef"的類型可以看成是const char[7]

5.sizeof是用來求類型的字節數的。

如int a;那么無論sizeof(int)或者是sizeof(a)都 是等於4,因為sizeof(a)其實就是sizeof(type of a)

6.對於函數參數列表中的以數組類型書寫的形式參數,編譯器把其解釋為普通 的指針類型

 

void func(char sa[100],int ia[20],char *p) 

則sa的類型為char*
ia的類型為int*
p的類型為char*

 

7.根據上面的總結,來實戰一下

1)對於char str[] = "abcdef";就有sizeof(str) == 7,因為str的類型是char[7] str本身可變

2)也有sizeof("abcdef") == 7,因為"abcdef"的類型是const char[7] 字符串常量

3)對於char *ptr = "abcdef";就有sizeof(ptr) == 4,因為ptr的類型是char*,即

 
         
#include <iostream>
#include <string>
using namespace std;
int main() {

    char *p = "hello";
    cout << sizeof(p) << endl;  //4
    cout << sizeof(char *) << endl; //4
    return 0;
}

 

4)對於char str2[10] = "abcdef";就有sizeof(str2) == 10,因為str2的類型是char[10]

5)對於void func(char sa[100],int ia[20],char *p);

 

sizeof(sa) == sizeof(ia) == sizeof(p) == 4

 

因為前面有說過編譯器把數組類型的書寫的形參,解釋為普通的指針類型

sa的類型是char*, ia的類型是int*,p的類型是char*

 

 

 

 

 

 

 

 

 

對於C/C++中的 字符指針和字符數組,總是在碰到的時候無法確定而不得不現場測試,來確定末尾是否包含'\0',函數到底如何使用等等。真是勞民傷財,現在總結一下:

字符指針的賦值

(1)指向一個字符串常量

char *src = "abcded"; //這種方式由系統自動給該字符指針指定了一個內存中的位置,並且該位置的字符數組為{'a', 'b', 'c', 'd', 'e', 'd', '\0'};

如果此時再次對 src賦值,src = "mmmt", 則src指向另外一個由系統指定的內存塊(由"mmmt"本身返回)。這種方式賦值的src為一個指向字符串常量指針,不能對src指向的位置的內容做改變的操作,即不能執行 *src = 'a', *(src+1) = 't' 等操作;但是可以改變src指向的位置,即像之前的 src = "mmmt";

(2)指向一個字符數組

char tmp[4] = {'a', 'c', 'e', 'f'};

char* src = tmp;  

(3)使用  new,然后可以像字符數組一樣賦值,即指向一個字符數組

char* src = new char[10]; //這種方式由程序在堆內存上開辟了一個數組,並將地址賦值給src

 

 

 

字符串常量和字符數組比較

 

(1)字符串常量由系統自動分配一個內存區域,且該區域中的內容不能改變(即無法通過指向該字符串的指針進行修改);

 

(2)字符數組或者為系統自動分配的全局數據區或棧上的內存,或者通過new操作來分配的堆上的內存,字符數組中的內容可變(即可以通過指向該字符數組的指針進行修改)

 

(3)字符數組中不默認含有'\0',除非明確賦值,而字符串常量在末尾自動含有 '\0'.

 

 

 

strcpy的使用

(1)用strcpy時候, 如果源字符串是一個字符指針,則沒有問題,因為字符指針自動帶'\0',在'\0'位置復制結束;

  而如果源是一個字符數組(即將字符數組轉換為字符指針來使用),則將會從字符數組的首地址開始復制,如果字符數組中明確指定了'\0'元素,則會在'\0'處停止,而若沒有'\0'元素,則程序可能會不停的復制,直到在程序的內存中碰到'\0',這樣可能會得到不希望的結果。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM