C初階4:字符串

1. 字符串操作

1.1 字符串遍歷

可以通過數(shù)組方式遍歷字符串拓挥。

char str[]="Hello World";
for(int i = 0;'\0' != str[i];++i){
    printf("%c\n",str[i]);
}

也可以使用指針方式

char str[]="Hello World";
for(int i = 0;'\0' != *(str+i);++i){
    printf("%c\n",*(str+i));
}

指針方式可以簡化成

char str[]="Hello World";
for(;'\0' != *str;++str){
    printf("%c\n",*str);
}

甚至是

while('\0' != *str){
    printf("%c\n",*str++);
}

while(*str){
    printf("%c\n",*str++);
}

1.2 字符串賦值

char s[] = "Hello World";
char* t;
t = s;
printf("%s\n",t);

沒有產(chǎn)生新的字符串蝠检,只是st指向相同的字符串。下面是查看兩個字符串的地址颅和。

printf("%p\n",s);
printf("%p\n",t);

試一試
字符串的修改

char s[] = "Hello World";
char* t;
t = s;
printf("%s\n",t);
t[1] = 'o';
printf("%s\n",s);
printf("%s\n",t);
s[4] = 'e';
printf("%s\n",s);
printf("%s\n",t);

指針能否反向賦值給字符串名元莫?

char s[] = "Hello World";
char* t;
t = s;
s = t;

1.3 字符串輸入輸出

char str[8];
scanf("%s",str);
printf("%s\n",str);

scanf()讀入一個單詞直到空白符(空格呜师、回車蓄愁、Tab)
scanf()不安全双炕,因為不知道要讀入的內(nèi)容長度,容易溢出撮抓。
例如:輸入123456789
解決方式:指定讀取的長度妇斤。

char str[8];
scanf("%7s",str);
printf("%s\n",str);

%s之間的數(shù)字表示最多允許輸入的字符數(shù),這個數(shù)字要比數(shù)組長度少1丹拯。

printf()輸出字符串的原理

char str[] = "Hello World";
for('\0'!=*str){
     printf("%s\n",str++);
}

字符串作為特例(傳地址)存在站超,可以整體scanf()printf()的原因在于結(jié)尾的\0

2. 字符串與函數(shù)

2.1 字符串傳參

字符串傳參方式與數(shù)組傳參方式一樣乖酬,只不過很多時候不需要傳遞字符串的長度(為什么死相?)。

void print_string(char str[]){
    printf(str);
}

或者

void print_string(char* str){
    printf(str);
}

2.2 字符串返回

字符串返回只能使用指針char*

3. 練習(xí)

  1. 交換
    實現(xiàn)字符串交換函數(shù)void swap(char* s1,char* s2)
  2. 拼接
    實現(xiàn)字符串拼接函數(shù)char* strcat(char* s1,char* s2)
  3. 拷貝
    實現(xiàn)字符串拷貝函數(shù)char* strcpy(char* s1,char* s2)
  4. 比較
    實現(xiàn)字符串相等判斷函數(shù)bool strcmp(char* s1,char* s2)

4. 字符串指針

數(shù)組可以用指針表示咬像。

字符數(shù)組可以直接初始化字符數(shù)組算撮,并且可以賦值給指針。

char s[]="Hello World";
char* p = s;
printf("%s\n",p);

字符串也可以直接賦值給指針县昂。這種指針稱為字符串指針肮柜。

char* str="Hello World";
printf("%s\n",str);

小結(jié)
字符數(shù)組和字符串指針初始化相似,只是形式上相似倒彰。

  • 字符數(shù)組本質(zhì)是數(shù)組审洞, char s[]="Hello World";可以看作下面代碼的簡化版。
    char s[]={'H','e','l','l','o',' ','W','o','r','l','d','\0'};
    
  • 字符串指針本質(zhì)是指針狸驳,char* p="Hello World";可以近似看作下面代碼的簡化版
    const char t[]="Hello World";
    char* p = t;
    

字符串指針與字符數(shù)組的區(qū)別有以下三點:

  1. sizeofstrlen()
  2. 字符是否可修改
  3. 地址是否可修改

4.1 sizeofstrlen()

#include <stdio.h>
#include <string.h>

int main(){
    char arr[] = "Hello World";
    char* ptr = "Hello World";
    printf("sizeof(arr) = %ld\n",sizeof(arr));
    printf("strlen(arr) = %ld\n",strlen(arr));
    printf("sizeof(ptr) = %ld\n",sizeof(ptr));
    printf("strlen(ptr) = %ld\n",strlen(ptr));
}

4.2 替換字符

試一下下面三個例子

  1. 修改字符數(shù)組
#include <stdio.h>
#include <string.h>

int main(){
    char arr[] = "Hello World";
    arr[0] = 'h';
    arr[6] = 'w';
    printf("%s\n",arr);    
}
  1. 字符串指針
#include <stdio.h>
#include <string.h>

int main(){
    char* ptr = "Hello World";;
    *ptr = 'h';
    *(ptr+6) = 'w';
    printf("%s\n",ptr);    
}
  1. 指向字符數(shù)組的字符串指針
#include <stdio.h>
#include <string.h>

int main(){
    char arr[] = "Hello World";
    char* ptr = arr;
    *ptr = 'h';
    *(ptr+6) = 'w';
    printf("%s\n",ptr);    
}

4.3 地址修改

char* p = "Hello";
p = "World";
char arr[] = "Hello";
arr = "World";

4.4 小結(jié)

字符串字面量初始化字符數(shù)組
字符串字面量初始化字符串指針

char* str1 = "Hello World";
char str2[] = "Hello World";

str1[5] = '\0'; // Error
str2[5] = '\0'; // OK

printf("str1=%s\n",str1);
printf("str2=%s\n",str2);

str1是一個指針预明,初始化指向一個字符串常量。(在C99標準中耙箍,str1報警告撰糠,提示應(yīng)該使用const char*)
修改字符串常量可能會導(dǎo)致嚴重后果。
str2是一個字符數(shù)組辩昆,初始化把字符串字面量自動復(fù)制到數(shù)組中阅酪。

如何選擇?

  1. 如果需要構(gòu)造字符串使用數(shù)組汁针;如果需要處理字符串使用指針(指向字符數(shù)組的指針)术辐。
  2. 字符串不需要修改使用字符串字面量初始化字符串指針。
  3. 字符串需要修改使用字符串字面量初始化字符數(shù)組施无。

決定字符串指針內(nèi)容能否修改的是指向的內(nèi)存辉词,而非指針。

5. 字符串const

  1. const字符數(shù)組
#include <stdio.h>
#include <string.h>

int main(){
    const char arr[] = "Hello World";
    arr[0] = 'h';
    arr[6] = 'w';
    printf("%s\n",arr);    
}
  1. 指向const字符數(shù)組的字符串指針
#include <stdio.h>
#include <string.h>

int main(){
    const char arr[] = "Hello World";
    char* ptr = arr;
    *ptr = 'h';
    *(ptr+6) = 'w';
    printf("%s\n",ptr);    
}

決定能否修改的是指針指向的值能否修改猾骡。const的限制只針對定義為const的變量瑞躺。


6. 字符串函數(shù)

6.1 字符串長度

size_t strlen(const char *s);

返回字符串長度不包含\0敷搪。

6.2 字符串比較

int strcmp(const char *s1,const char *s2);

比較兩個字符串
返回0,表示s1 == s2
返回>0幢哨,表示s1 > s2
返回<0赡勘,表示s1 < s2
為什么字符串不能直接比較?
為什么字符串比較會有大欣塘闸与?

6.3 字符串拷貝

char* strcpy(char* restrict dst,const char* restrict src);

把字符換src拷貝到dst。

restrict是C99關(guān)鍵字岸售,表示指針指向內(nèi)存只使用當前指針修改践樱,便于編譯器優(yōu)化。在這里可表示dstsrc內(nèi)存不存在重疊冰评,便于并行處理映胁。同時告知使用方不要使用重疊內(nèi)存的兩個指針使用該函數(shù)。

返回值為dst甲雅,便于連接解孙。
連續(xù)賦值。

復(fù)制一個字符串

// char* dst = (char*)malloc(strlen(src)+1);
char dst[strlen(src)+1];
strcpy(dst,src);

6.4 字符串連接

char* strcat(char* restrict s1,const char*restrict s2);

把s2拷貝到s1的后面抛人,拼接成一個長的字符串弛姜。
返回s1,注意:s1必須有足夠的空間。

char* a="Hello";
char* b="World";
char res[strlen(a)+strlen(b)+1] = {0};
strcat(strcat(res,a),b);

strcpy和strcat都會有安全問題:dst空間不足妖枚,出現(xiàn)越界廷臼。

6.5 字符查找

char* strchr(const char*s,int c);
char* strrchr(const char*s,int c);

返回找到字符的指針,沒找到返回NULL
如何查找第二個绝页?

6.6 子串查找

char* strstr(const char*s1,const char*s2);
char* strcasestr(const char*s1,const char*s2);

7. 文檔

學(xué)會通過例子荠商,學(xué)會函數(shù)的使用。

stdio.h

  • sprintf:數(shù)據(jù)按格式寫入字符串
  • sscanf:按格式從字符串讀出數(shù)據(jù)

stdlib.h

  • atof:字符串轉(zhuǎn)浮點數(shù)
  • atoi:字符串轉(zhuǎn)整數(shù)
  • atol:字符串轉(zhuǎn)長整數(shù)

string.h

復(fù)制

  • strcpy:字符串拷貝
  • strncpy:指定個數(shù)字符串拷貝

連接

  • strcat:字符串連接
  • strncat:指定個數(shù)字符串連接

比較

  • strcmp:字符串比較
  • strncmp:指定個數(shù)字符串比較

查找

  • strchr:查找字符串中第一個出現(xiàn)指定字符的位置
  • strrchr:查找字符串中最后一個出現(xiàn)指定字符的位置
  • strstr:查找字符串中第一個出現(xiàn)指定子串的位置
  • strtok:切分字符串

其他

練習(xí)
實現(xiàn)函數(shù)times(char* dst,int n,char* src)

8. 實踐

  1. 已知十天干和十二地支
    天干:甲续誉、乙莱没、丙、丁酷鸦、戊饰躲、己、庚臼隔、辛嘹裂、壬、癸
    地支:子摔握、丑寄狼、寅、卯氨淌、辰例嘱、巳狡逢、午、未拼卵、申、酉蛮艰、戌腋腮、亥
    按順序打印出六十甲子
    甲子、乙丑壤蚜、丙寅即寡、丁卯、戊辰袜刷、己巳聪富、庚午、辛未著蟹、壬申墩蔓、癸酉、
    甲戌萧豆、乙亥奸披、丙子、丁丑涮雷、戊寅阵面、己卯、庚辰洪鸭、辛巳样刷、壬午、癸未览爵、
    甲申置鼻、乙酉、丙戌拾枣、丁亥沃疮、戊子、己丑梅肤、庚寅司蔬、辛卯、壬辰姨蝴、癸巳俊啼、
    甲午、乙未左医、丙申授帕、丁酉同木、戊戌、己亥跛十、庚子彤路、辛丑、壬寅芥映、癸卯洲尊、
    甲辰、乙巳奈偏、丙午坞嘀、丁未、戊申惊来、己酉丽涩、庚戌、辛亥裁蚁、壬子矢渊、癸丑、
    甲寅厘擂、乙卯昆淡、丙辰、丁巳刽严、戊午昂灵、己未、庚申舞萄、辛酉眨补、壬戌、癸亥
  1. 已知今年的紀年倒脓,輸入21世紀任意年份撑螺,打印出對應(yīng)的甲子。
  2. 已知今年的紀年崎弃,打印出21世紀所有年份的甲子甘晤。
  3. 已知小明同學(xué)的屬相,推斷出可能的年齡饲做。

9. 擴展

char*一定是字符串嗎线婚?
char*不一定是字符串,只有以0結(jié)尾的字符數(shù)組才是字符串盆均。

9.1 0塞弊、'\0''0'

0'\0'

'\0'表示字符串的結(jié)束,但不是字符串的一部分。計算字符串長度時不包含'\0'游沿。

字符串以數(shù)組方式存儲饰抒,可以用數(shù)組或者指針形式訪問。

9.2 空字符串

char str[10]="";

這是一個空字符串诀黍,str[0]\0袋坑。

char str[]="";

這是也是一個空字符串,str數(shù)組長度為1眯勾。

常見錯誤:使用未初始化的char*

char* str;
printf("%s\n",str);

同常如果指針定義時無法確定初始值時咒彤,使用NULL初始化指針。

9.3 字符串常量連接

兩個相鄰字符串常量會自動連接咒精。

char greeting = "Hello" "World";
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市旷档,隨后出現(xiàn)的幾起案子模叙,更是在濱河造成了極大的恐慌,老刑警劉巖鞋屈,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件范咨,死亡現(xiàn)場離奇詭異,居然都是意外死亡厂庇,警方通過查閱死者的電腦和手機渠啊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來权旷,“玉大人替蛉,你說我怎么就攤上這事≈袈龋” “怎么了躲查?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長译柏。 經(jīng)常有香客問我镣煮,道長,這世上最難降的妖魔是什么鄙麦? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任典唇,我火速辦了婚禮,結(jié)果婚禮上胯府,老公的妹妹穿的比我還像新娘介衔。我一直安慰自己,他們只是感情好盟劫,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布夜牡。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪塘装。 梳的紋絲不亂的頭發(fā)上急迂,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音蹦肴,去河邊找鬼僚碎。 笑死,一個胖子當著我的面吹牛阴幌,可吹牛的內(nèi)容都是我干的勺阐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼矛双,長吁一口氣:“原來是場噩夢啊……” “哼渊抽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起议忽,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤懒闷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后栈幸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愤估,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年速址,在試婚紗的時候發(fā)現(xiàn)自己被綠了玩焰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡芍锚,死狀恐怖昔园,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闹炉,我是刑警寧澤蒿赢,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站渣触,受9級特大地震影響羡棵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嗅钻,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一皂冰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧养篓,春花似錦秃流、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽概说。三九已至,卻和暖如春嚣伐,著一層夾襖步出監(jiān)牢的瞬間糖赔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工轩端, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留放典,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓基茵,卻偏偏與公主長得像奋构,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拱层,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1)字符串操作strcpy(p, p1) 復(fù)制字符串strncpy(p, p1, n) 復(fù)制指定長度字符串strc...
    XDgbh閱讀 4,421評論 0 10
  • 本文轉(zhuǎn)自:http://www.cnblogs.com/lidabo/p/5225868.html 1)字符串操作...
    XiaohuiLI閱讀 9,515評論 0 0
  • 一弥臼、字符串操作 strcpy(p, p1) 復(fù)制字符串 strncpy(p, p1, n) 復(fù)制指定長度字符串 s...
    JaiUnChat閱讀 1,659評論 0 7
  • 在C語言中,五種基本數(shù)據(jù)類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,342評論 0 2
  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運用指針編程是C語言最主要的風(fēng)格之一根灯。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu)醋火; ...
    朱森閱讀 3,444評論 3 44