一、文字常量區域
#include <stdio.h>
int main()
{
char *p = "hello";
int i = 0;
for(i = 0;i<6;i++)
{
printf("%c",*(p+i));
}
*p = '1';
}
大家分析驗證以上代碼,p 是一個指針變量,存儲位址,“hello”是一個字元串占6個位元組,當我們用printf的時候能夠輸出"hello",我們得出結論,p存儲的是存放‘h’的記憶體的位址,當我們*p = '1',去寫這塊記憶體的時候,會出現段錯誤。
根據以上現象,我們引出下面概念:
"hello"存放在 文字常量區,這個區用來存放代碼中出現的字元串常量,并且這塊記憶體區域隻能讀不能寫,以下對程式記憶體做總結:
二、程式記憶體總結
程式運作起來後分為一下幾塊記憶體區域:
1、代碼區
存放各種語句生成的指令。
2、文字常量區
字元串常量放在這裡。
比如 char *p = "hello";
3、棧區
局部變量,由系統自動申請釋放,生存周期為子產品開始到子產品結束。
4、堆區
malloc free,由程式員自己申請釋放。
5、靜态存儲區
全局變量 static 變量放在這裡,程式開始申請出來,程式結束釋放。
三、結合代碼綜合分析
#include <stdio.h>
char a[10] = "hello"; //“hello”字元串存儲在全局數組中,在 靜态存儲區。
int main()
{
char b[10] = "hello"; //“hello”存儲在數組b中,在棧區。
char *p1 = "hello"; //“hello”存儲在文字常量區,p1存儲了存放‘h’的記憶體的位址,p1在棧區。
char *p2 = NULL;//p2 在棧區
*p = '1';//錯誤,這塊區域隻能讀。
p2 = (char*)malloc(10);// 在堆中申請10個位元組的記憶體,并把這塊記憶體的位址存放在p2中。
strcpy(p2,"hello");//把"hello"字元串拷貝到堆記憶體中。
free(p2);
}
四、字元串操作函數的基本原理
1、printf
原型 int printf(const char* p,...);
關于const與指針 參考 http://blog.csdn.net/xiaoliu0518/article/details/32943713
printf函數是一個可變參數函數,參數個數不定,第一個參數是const char* p ,p 存放字元串的位址,通過這個字元串的内容去解析後面的變量然後輸出相應的内容。
比如 printf("%c",...);
當字元串為"%c"的時候,printf原型可簡單了解為 printf("%c",char c),列印字元。
在比如printf("%s",...)
當字元串為"%s"的時候,printf的原型可以簡單了解為 printf("%s",const char *p),在printf中會一個一個列印字元,簡單邏輯如下:
int printf("%s",const char *p)
{
while(*p != '\0')
{
putchar(*p);
p++;
}
}
是以這裡知道為什麼,%s的時候,後面可以傳char 數組、字元串常量、char* str了吧,因為形參是const char *p。
char a[10] = "hello";
printf("%s","hello");
printf("%s",a);
2、strlen
strlen簡單邏輯如下,依然是判斷'\0'結束
int strlen(const char *str)
{
int len = 0;
while(*str != '\0')
{
len++;
str++;
}
return len;
}
根據形參,可以有以下調用
strlen(字元串常量)
strlen(數組名)
strlen(char*指針)
3、strcpy
strcpy簡單邏輯如下,依然是判斷'\0'結束
void strcpy(char *dest,const char* src)
{
while(*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = '\0';
}
通過以上三個例子,簡單了解字元串相關函數的操作原理,注意都是要判斷'\0',如果沒有'\0',則位址一直往後加,就會通路到非法記憶體。
以上3個例子隻寫簡單邏輯,并沒有考慮安全性,嚴謹性,大家可以自己實作下 strlen strcpy。
再考慮 如下:
char *p = "hello";
char a[10] = "hello";
printf("%s",p);
strcpy(p,"bye");
printf("%s",a);
strcpy(a,"bye");
哪些代碼有問題?