你知道char *s和char s[]的区别吗?
在一個夜深人靜的晚上,有一個讀者給我發了一個C語言題目。他問我,發哥,幫我看看這個代碼有什么問題。我看了代碼之后,心里一陣恐慌。我自認為我不是C語言高手。但我確實是一個喜歡解決問題的男人。就是在這樣的背景驅使下,我寫下了這篇文章。
char *str1 = "hello"; char str2[] = "hello";我們看這兩個定義。我們說這個是定義而不是聲明,是因為定義在內存里面分配了房子。而聲明,只給了個房產證卻不給你分房子。
str1 是 char *類型 。它是一個指針,這個指針指向一個字符串。
str2 是 char [] 類型。它是一個數組,他代表了這堆內存空間。
“hello”字符串在內存中是這樣存放的
我之前寫過一個不同變量地址分配在內存不同區域的文章,有不清晰的可以再回去看看。
str1 str3都是指向字符串的指針,而且這個字符串是保存在字符串常量區的。這個常量區里面的東西是不能被修改的。編譯器讓他們指向了同一個地址。這個地址保存的東西是 “hello”這個字符串。
大家看看下面這個代碼有什么問題?
#include "stdio.h" #include "stdlib.h" #include "string.h"int main(void) {char *str1 = "hello";char *str3 = "hello";char str2[] = "hello";memcpy(str3,"worldtest",strlen("worldtest")+1);printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);str3 = "world";printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);printf("hello,world\n");return (0); }memcpy嘗試向一個非法的地址拷貝東西,這個是不允許的。為什么說這個地址非法呢?因為字符常量區里面的內容,只可以讀,不可以寫。
如果改成這樣的呢?應該輸出什么結果呢?
#include "stdio.h" #include "stdlib.h" #include "string.h"int main(void) {char *str1 = "hello";char *str3 = "hello";char str2[] = "hello";//memcpy(str3,"worldtest",strlen("worldtest")+1);printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);str3 = "world";printf("str1:%s str3:%s str2:%s\n",str1,str3,str2);printf("hello,world\n");return (0); }我之前在文章里面討論一個問題,我們說指針的時候,要說指針變量。指針變量保存的內容是一個地址。既然是變量,那么保存的地址是可以變化的。只要類型符合。都可以保存。
同樣的,在上面的例子中,如果我們嘗試這樣
str1[1] = 'a';這樣也是錯誤的。這樣也是寫操作了非法的地址。
試試下面這段代碼
#include <stdio.h> int main(){char* str1="Hello";printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));str1 = "world";printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));return 1; }輸出
str1: Hello, address: 0000000000404000, sizeof(str1): 8 str1: world, address: 0000000000404031, sizeof(str1): 8 -------------------------------- Process exited after 0.0226 seconds with return value 1 請按任意鍵繼續. . .通過賦值運算后,str1的值也發生了改變。
但是str2情況會不一樣,str2是一個數組。
既然是數組,我們看看這段小代碼
#include<stdio.h> int main(){char str2[] = "hello";printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));str2[2] = 'A';printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));strcpy(str2, "world");printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));return 1; }輸出日志
str2: hello, address: 000000000062FE10, sizeof(str2): 6 str2: heAlo, address: 000000000062FE10, sizeof(str2): 6 str2: world, address: 000000000062FE10, sizeof(str2): 6 -------------------------------- Process exited after 0.04063 seconds with return value 1 請按任意鍵繼續. . .送一個圖
晚上回來我寫了一個小程序。大家看看
#include <stdio.h> #include "stdlib.h" #include "string.h"const int a = 1; const int a1 = 1; char * s = "hello";int main() {const int b = 2;const int b1 = 2;char * s1 = "hello";printf("s:%p s1:%p\n",s,s1);printf("a:%p a1:%p b:%p b1:%p\n",&a,&a1,&b,&b1);return 1; }輸出如下:
s:0000000000404008 s1:0000000000404008 a:0000000000404000 a1:0000000000404004 b:000000000062FE14 b1:000000000062FE10-------------------------------- Process exited after 0.03901 seconds with return value 1 請按任意鍵繼續. . .可以看到,s,s1,a,a1在一個內存區域。這個內存區域的內容是不允許改變的。如果你對這里的內存區域賦值,就會出現段錯誤。
但是b和b1這個內存區域大家看看。我們可以寫個小代碼測試一下。
#include <stdio.h> #include "stdlib.h" #include "string.h"const int b = 2;int main() {const int b1 = 2;int *p = &b1;printf("b1:%d\n",b1);*p = 3;printf("b1:%d\n",b1);return 1; }輸出:
b1:2 b1:3-------------------------------- Process exited after 0.0403 seconds with return value 1 請按任意鍵繼續. . .但是我們寫成這樣呢?
#include <stdio.h> #include "stdlib.h" #include "string.h"const int b = 2;int main() {const int b1 = 2;int *p = &b;printf("b:%d\n",b);*p = 3;printf("b:%d\n",b);return 1; }輸出:
b:2-------------------------------- Process exited after 3.743 seconds with return value 3221225477 請按任意鍵繼續. . .如果放到gcc下,可以看到,執行到代碼
*p = 3;會出現段錯誤。因為訪問了不能訪問的地址。這也就是我們很多時候給空指針賦值出現段錯誤的原因。操作了非法的地址。
好了,就瞎BB這么多,如果覺得有用,可以留言一起討論下。
? 回復「?籃球的大肚子」進入技術群聊
回復「1024」獲取1000G學習資料
總結
以上是生活随笔為你收集整理的你知道char *s和char s[]的区别吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为电脑管家PcManager多屏协同功
- 下一篇: 你应该知道Linux内核softirq