c语言 指针到字符串,C语言中的指针和字符串
前言
務(wù)必理解指針與內(nèi)存模型,不要死記硬背。
內(nèi)存里的字符串
C語言中的字符串一般是char *類型的,這是怎樣存在內(nèi)存中的呢?
cchar *s = "NIHAO";
| s:400 |
|---|---|---|---|
|'N'|'I'|'H'|'A'|'O'| 0 |
|---|---|---|---|---|---|
|400|401|402|403|404|405|
如是上圖,假設(shè)字母A處于內(nèi)存的第400號(hào)格子,那么后面幾個(gè)字母也是緊跟著的。
變量s本身并沒有儲(chǔ)存字符串,而存的是字符串的首地址400。也即,s指向這個(gè)字符串。
為什么沒有專門一個(gè)字符串的類型而是要靠一個(gè)指針指向它呢?因?yàn)樽址拈L(zhǎng)度是不固定的,所以一個(gè)字符串還包含著長(zhǎng)度信息,基本類型是無法處理數(shù)據(jù)結(jié)構(gòu)的。
我們都知道字符串是以0結(jié)尾的,而且這個(gè)更像是一種約定,C編譯器本身并沒有對(duì)此做任何保證。比如這樣
cchar s[3] = "asd";
puts(s); /* prints "asd" or something longer */
這樣做是危險(xiǎn)的,因?yàn)閟只有3個(gè)格子,字符串結(jié)尾的0并沒有放進(jìn)去。如果在它后面的內(nèi)存格子并不是0,那打印這個(gè)字符串時(shí)就跟我們預(yù)期的不一樣了。
字符串常量不可寫
c"abc"[0] = 'z'; /* wrong */
char *s = "abc";
s[0] = 'z'; /* wrong */
char s[5] = "abc";
s[0] = 'z' /* right */
當(dāng)指針s指向的是字符串常量(即直接寫在程序里面的字符串時(shí)),要注意它是不可寫的
為啥用數(shù)組就沒問題呢,因?yàn)閿?shù)組的初始化和指針有點(diǎn)區(qū)別
cchar s[5] = "abc";
/* 相當(dāng)于 */
char s[5];
strcpy(s, "abc");
如果擔(dān)心自己會(huì)不小心寫錯(cuò),可以加上const關(guān)鍵字,這樣編譯的時(shí)候就會(huì)報(bào)錯(cuò)
這是一個(gè)好習(xí)慣,接下來的示例程序中都會(huì)這么寫。
cconst char *s = "abc";
s[0] = 'z'; /* causes a compiling error instead of runtime error */
指針是要初始化才能使用的
c/* wrong */
char *s;
s[0];
上面的程序編譯是能過的(可能有warning),但運(yùn)行是一定會(huì)出錯(cuò)的,因?yàn)榫幾g器并不知道s指向哪些格子。
c/* right */
const char *s = "NIHAO";
s[0];
這樣,其實(shí)是隱式的分配了6個(gè)格子(包括字符串結(jié)尾的0),并讓s指向它們
c/* right */
char s[6];
s[0];
c/* right */
char s[6] = "NIHAO";
s[0];
數(shù)組其實(shí)跟指針沒什么區(qū)別,主要的區(qū)別是它在聲明的時(shí)候就分配好了格子(方括號(hào)里的6就是告訴編譯器給我6個(gè)格子),而且數(shù)組不能改變它的指向(也不能再要更多的格子)。
為什么不能用等號(hào)來比較字符串?
比較字符串
cconst char *s = "abcd";
const char *t = "abcd";
/* wrong */
if (s == t) {
...
}
/* right */
if (!strcmp(s, t)) {
...
}
因?yàn)閟和t都沒有存字符串的內(nèi)容,它們存的是字符串的地址,如果用==比較,比較的是兩個(gè)字符串的地址是否相同。我們希望比較的是內(nèi)容是否相同。
請(qǐng)使用C語言庫函數(shù)中的strcmp比較字符串是否相等
復(fù)制字符串
c/* tries to copy a string */
char s[5] = "abcd";
char *t = s;
t[3] = 'z';
puts(s); /* puts "abcz" */
上面這種做法讓t和s指向同一字符串,修改t指向的內(nèi)容,會(huì)發(fā)現(xiàn)s指向的內(nèi)容也被修改了。這種做法沒有錯(cuò),經(jīng)常會(huì)用到,但不一定是你想要的。
c/* wrong */
char *s = "abcd";
char *t; /* not initialized */
strcpy(t, s);
c/* right */
char *s = "abcd";
char t[10] = {0}; /* or char *t = (char *) malloc(5*sizeof(char)); */
strcpy(t, s);
使用strcpy復(fù)制字符串的內(nèi)容而不是指針,但也要注意初始化t這個(gè)指針
怎樣讓函數(shù)得到一個(gè)字符串結(jié)果
int,float之類的很簡(jiǎn)單直接return就好
但現(xiàn)在我想寫一個(gè)函數(shù),它能夠得到一個(gè)字符串
三種錯(cuò)誤的或者不太好的做法
c/* no problem, but meaningless */
const char *f()
{
const char *s = "abcd";
return s;
}
/* wrong */
char *f()
{
char s[100];
/* do something with s */
return s;
}
/* result correct but not good */
char *f()
{
int n = 10;
char *s = (char *) malloc(n*sizeof(char));
/* do something with s */
return s;
}
第一種情況就不說了,返回一個(gè)字符串常量并沒有問題因?yàn)樗豢尚薷?#xff0c;但是不可修改也就沒什么意義了。
第二種情況是完全錯(cuò)誤的,返回一個(gè)局部的數(shù)組。這個(gè)數(shù)組的內(nèi)存會(huì)在函數(shù)調(diào)用完后被收回,因此返回的指針指向的時(shí)候沒有意義的地方。現(xiàn)代編譯器一般都會(huì)對(duì)這個(gè)有warning。
第三種情況是返回malloc的指針。這種情況你可以得到正確的答案,但是不推薦,調(diào)用這個(gè)函數(shù)的人很有可能
不知道函數(shù)里面分配過內(nèi)存
不知道應(yīng)該什么時(shí)候free這部分內(nèi)存
忘了free這部分內(nèi)存
一旦沒有注意,多次調(diào)用這個(gè)函數(shù),結(jié)果就是內(nèi)存溢出,這樣的錯(cuò)誤還非常不好排查,所以不推薦
正確的做法
正確的做法是把分配內(nèi)存這種事情放在函數(shù)外面做,正如strcpy一樣
cchar *strcpy(char *dest, const char *src)
{
int i;
for (i = 0; i < strlen(src); i++) {
dest[i] = src[i];
}
return dest;
}
dest是我們想要返回的字符串,它是從外面?zhèn)鬟M(jìn)來的原因是我們不想在函數(shù)內(nèi)部為它分配內(nèi)存,而是在外面分配好了,里面只對(duì)這個(gè)字符串進(jìn)行修改。
注意這里返回了char *但其實(shí)返回的正是原本傳進(jìn)來的dest,這里只是為了方便而已。
總結(jié)
以上是生活随笔為你收集整理的c语言 指针到字符串,C语言中的指针和字符串的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 命令 抛后台,Linux 后
- 下一篇: c语言程序设计徐立辉答案,C语言程序设计