自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C語言中的字符串操作函數(shù)

開發(fā) 后端
我們知道,c/c++之所以使用起來靈活,很大原因歸因于它能夠它對能夠?qū)?nèi)存的直接操作,所以本文我主要講述一下c中的字符串操作函數(shù)。

 [[428946]]

本文轉(zhuǎn)載自微信公眾號「編碼珠璣」,作者劉亞曦。轉(zhuǎn)載本文請聯(lián)系編碼珠璣公眾號。

我們知道,c/c++之所以使用起來靈活,很大原因歸因于它能夠它對能夠?qū)?nèi)存的直接操作,所以本文我主要講述一下c中的字符串操作函數(shù)。

一、常量指針與指針常量

先來補(bǔ)充一個(gè)上篇文章 手把手教你深入理解c/c++中的指針 我在講述指針中的一個(gè)問題,有人說常量指針與指針常量這兩個(gè)概念總是混淆怎么辦,例如:

  1. int a = 100; 
  2. const int * p = &a;  //常量指針,指向的值不可更改,但指向的地址可以更改 
  3. int const * p = &a;  //與上式等價(jià) 
  4. int * const p = &a;  //指針常量,指向的地址不可以更改,但指向的值可更改 

那么究竟如何區(qū)分常量指針與指針常量呢,這里邊有個(gè)技巧,上篇文章中我忘記給大家說了:

從左往右看,跳過類型,看修飾哪個(gè)字符,如果是*, 說明指針指向的值不能改變,如果是指針變量,說明指針的指向不能改變,指針的值不能修改。這個(gè)原則你可以通俗理解成 “就近原則”。

那么回頭來看第一行代碼,也就是指針常量:

  1. const int * p = &a; 

我們跳過變量類型 int ,那么const修飾的是*,所以它指向的值不能修改

第二行代碼,常量指針:

  1. int * const p = &a; 

同樣,我們跳過int,發(fā)現(xiàn)const是直接修飾的p,所以它的指向不能改變。兩者有細(xì)微的差別,請大家注意。

我們再回到本節(jié)的字符串問題上,在講述字符串拷貝函數(shù)前,我們再來回憶一下c語言中的字符串。

我們知道,c語言中的字符串有兩種定義的方法,分別是:

  1. char str1[] = "hello world";  //棧區(qū)字符串 
  2. char* str2 = "hello world";  //數(shù)據(jù)常量區(qū)字符串 

那么這兩種在使用起來究竟有什么區(qū)別呢?答案是第一行定以后,操作系統(tǒng)給它分配的是棧區(qū)內(nèi)存,而第二行通過指針形式來定義字符串的話,它分配的內(nèi)存區(qū)在數(shù)據(jù)的常量區(qū),意味著它的值是不可更改的:

  1. str1[0] = 'm';  //正確,字符數(shù)組可以修改 
  2. str2[0] = 'm';  //錯(cuò)誤,常量區(qū)不可修改 

所以,在常量區(qū),如果我們兩個(gè)內(nèi)容相同但變量不同的指針變量,其實(shí)它們指向的是同一塊內(nèi)存:

  1. char* str1 = "hello world";   
  2. char* str2 = "hello world";   
  3. printf("%p\n",str1); 
  4. printf("%p\n",str2); 

上面兩行代碼中,我們將str1與str2指向的內(nèi)存地址分別打印出來,發(fā)現(xiàn)他們的值是一樣的,為什么呢,這是因?yàn)槌A繀^(qū)內(nèi)存的值是只讀的,我們即便聲明兩個(gè)不同的變量,只要他們的值是相同的,那么兩個(gè)變量指向的就是同一塊內(nèi)存區(qū)域。

這里值得注意的是,在c++中,字符串指針與c語言中稍有區(qū)別,c++中直接將字符串指針做了增強(qiáng)處理,因?yàn)閏++中規(guī)定字符串指針必須用const修飾,例如在c++中這樣定義,編譯器會直接報(bào)錯(cuò):

  1. char* str = "hello world";  //直接報(bào)錯(cuò) 
  2. const char * str = "hello world";  //正確 

而在實(shí)際開發(fā)過程中,我們使用字符串一般使用數(shù)組形式,不太建議使用指針字符串形式,也即:

  1. char str[] = "hello world";  //建議使用 
  2. char* str = "hello world";  //不建議使用 

所以,這方面細(xì)微的差別請大家注意。

二、字符串長度問題

我們知道c語言中的字符串是以 '\0' 為結(jié)尾的,也就是說你在聲明一個(gè)字符串的時(shí)候,系統(tǒng)會自動為你的結(jié)尾添加上一個(gè)以 '\0' 為結(jié)尾的結(jié)束字符,而且,printf 在每打印一個(gè)字符就會檢查當(dāng)前字符是否為 ‘\0’ ,直到遇到 '\0' 立馬停止。這里最容易混淆的的是字符串的長度,我們來看下面兩行代碼:

我們先來看下面兩行代碼:

  1. char str1[] = "hello"
  2. char* str2 = "hello"
  3. printf("%d\n", sizeof(str1));  //輸出結(jié)果為 6 
  4. printf("%d\n", sizeof(str2));  //輸出結(jié)果為 4 或者 8 

那么為什么在使用 sizeof 計(jì)算字符串長度,兩者計(jì)算出來的結(jié)果不一樣呢,而且第一行長度還不是我們想要的,不應(yīng)該是 5 才對嗎?這是因?yàn)樵诼暶饕粋€(gè)字符串的時(shí)候,系統(tǒng)會自動為你的結(jié)尾添加上一個(gè)以 '\0' 為結(jié)尾的結(jié)束字符,內(nèi)存模型如下:

所以,對于上面兩行代碼,實(shí)際上它們的長度都為 6 才對。那為什么第二行輸出卻為 4 呢,這是因?yàn)榈诙形覀兌x的是一個(gè)字符串指針,它指向一個(gè)常量區(qū)的字符串,而 sizeof 操作符操作這個(gè)指針的時(shí)候,實(shí)際上計(jì)算的是這個(gè)指針的字節(jié)長度,而一個(gè)指針在x86系統(tǒng)下占有長度為 4 字節(jié),在x64環(huán)境下占有長度為 8 字節(jié),所以,在實(shí)際上我們計(jì)算字符串長度的時(shí)候,一般會用 strlen() 這個(gè)函數(shù),但是要注意,strlen 計(jì)算字符串也是以 '\0' 為結(jié)束的,也就是說,strlen() 函數(shù)會不斷判斷當(dāng)前字符是否為 '\0',如果是的話,立馬結(jié)束,這個(gè)特點(diǎn)與printf函數(shù)一樣,兩者都是碰到 '\0' 就立馬結(jié)束:

  1. char str1[] = "abc"
  2. char str2[] =  {'a''\0''c'}; 
  3. char str3[] =  {'a''b''c''\0'}; 
  4. char* str4 = "abc"
  5. printf("%d\n", strlen(str1));  //輸出結(jié)果為 3 
  6. printf("%d\n", strlen(str2));  //輸出結(jié)果為 1 
  7. printf("%d\n", strlen(str3));  //輸出結(jié)果為 3 
  8. printf("%d\n", strlen(str4));  //輸出結(jié)果為 3 

上面就是c語言中的字符串長度函數(shù),在使用過程中千萬要注意。

三、C語言中的字符串拷貝函數(shù)

1) strcpy()

  1. #include <string.h> 
  2. char *strcpy(char *dest, const char *src); 
  3. //功能:把src所指向的字符串復(fù)制到dest所指向的空間中,'\0'也會拷貝過去 
  4. 參數(shù): 
  5.   dest:目的字符串首地址 
  6.   src:源字符首地 
  7. 返回值: 
  8.   成功:返回dest字符串的首地址 
  9.   失敗:NULL 

示意代碼如下:

  1. #define _CRT_SECURE_NO_WARNINGS 
  2.   #include <string.h> 
  3.   char str[10] = { 0 }; 
  4.   char str1[] = "hello"
  5.   char* mystr = strcpy(str, str1);  將strcpy返回的指針保存到mystr里面 
  6.   printf(mystr); 

內(nèi)存模型如下:

由于是逐個(gè)拷貝,意味著哪怕在字符串的中間遇到了 '\0' 字符,也會結(jié)束拷貝。

這里邊要注意兩個(gè)問題:第一,必須保證 dest 所指向的內(nèi)存空間足夠大,否則可能會造成緩沖溢出的錯(cuò)誤;第二,由于本身strcpy函數(shù)是一個(gè)非安全函數(shù),所以編譯器會彈出警告,要想忽略,請?jiān)诔绦蜃铋_頭添加宏定義代碼:

  1. #define _CRT_SECURE_NO_WARNINGS 

2)strncpy()

  1. #include <string.h> 
  2. char *strncpy(char *dest, const char *src, size_t n); 
  3. 功能: 
  4.   把src指向字符串的前n個(gè)字符復(fù)制到dest所指向的空間中, 
  5.   是否拷貝結(jié)束符看指定的長度是否包含'\0'。 
  6. 參數(shù): 
  7.   dest:目的字符串首地址 
  8.   src:源字符首地址 
  9.   n:指定需要拷貝字符串個(gè)數(shù) 
  10. 返回值: 
  11.   成功:返回dest字符串的首地址 
  12.   失?。?span id="k6zqhab033oa" class="op">NULL 

這個(gè)函數(shù)與strcpy類似,這里不再累贅。

3)strcat()

  1. #include <string.h> 
  2. char *strcat(char *dest, const char *src); 
  3. 功能:將src字符串連接到dest的尾部,‘\0’也會追加過去 
  4. 參數(shù): 
  5.   dest:目的字符串首地址 
  6.   src:源字符首地址 
  7. 返回值: 
  8.   成功:返回dest字符串的首地址 
  9.   失?。?span id="k6zqhab033oa" class="op">NULL 

這是一個(gè)字符串追加函數(shù),將 src 指向的字符串追加到 dest 指向的字符串后面,同樣,結(jié)束符 '\0' 也會追加過去:

  1. #define _CRT_SECURE_NO_WARNINGS 
  2.   #include <string.h> 
  3.   char str[] = "123"
  4.   char str1[] = "hello"
  5.   char* mystr = strcat(str, str1); 
  6.   printf("%s\n%p", mystr, mystr);   
  7.   //輸出結(jié)果為:123hello 

但是同樣注意的是,目標(biāo)字符串 dest 要有足夠大的緩沖區(qū)來接收,否則會報(bào)錯(cuò),內(nèi)存模型如下:

4)strncat()

  1. #include <string.h> 
  2. char *strncat(char *dest, const char *src, size_t n); 
  3. 功能:將src字符串前n個(gè)字符連接到dest的尾部,‘\0’也會追加過去 
  4. 參數(shù): 
  5.   dest:目的字符串首地址 
  6.   src:源字符首地址 
  7.   n:指定需要追加字符串個(gè)數(shù) 
  8. 返回值: 
  9.   成功:返回dest字符串的首地址 
  10.   失?。?span id="k6zqhab033oa" class="op">NULL 

這個(gè)函數(shù)與strcat類似,只不過指定了追加的數(shù)量。

5)strcmp()

  1. #include <string.h> 
  2. char *strcat(char *dest, const char *src); 
  3. 功能:將src字符串連接到dest的尾部,‘\0’也會追加過去 
  4. 參數(shù): 
  5.   dest:目的字符串首地址 
  6.   src:源字符首地址 
  7. 返回值: 
  8.   成功:返回dest字符串的首地址 
  9.   失?。?span id="k6zqhab033oa" class="op">NULL 

作用是對兩個(gè)字符串的ASCII碼進(jìn)行比較,輸出不同結(jié)果,經(jīng)常用于判斷兩個(gè)字符串是否相等,示例代碼如下:

  1. char *str1 = "hello world"
  2. char *str2 = "hello mike"
  3.  
  4. if (strcmp(str1, str2) == 0) 
  5.   printf("str1==str2\n"); 
  6. else if (strcmp(str1, str2) > 0) 
  7.   printf("str1>str2\n"); 
  8. }   
  9. else 
  10.   printf("str1<str2\n"); 

6)strncmp()

  1. #include <string.h> 
  2. int strncmp(const char *s1, const char *s2, size_t n); 
  3. 功能:比較 s1 和 s2 前n個(gè)字符的大小,比較的是字符ASCII碼大小。 
  4. 參數(shù): 
  5.   s1:字符串1首地址 
  6.   s2:字符串2首地址 
  7.   n:指定比較字符串的數(shù)量 
  8. 返回值: 
  9.   相等:0 
  10.   大于:> 0 
  11.   小于: < 0 

這個(gè)函數(shù)作用也是與strcmp類似,不再累贅。

7)sprintf()

  1. #include <stdio.h> 
  2. int sprintf(char *str, const char *format, ...); 
  3. 功能:根據(jù)參數(shù)format字符串來轉(zhuǎn)換并格式化數(shù)據(jù), 
  4.       然后將結(jié)果輸出到str指定的空間中, 
  5.       直到出現(xiàn)字符串結(jié)束符 '\0' 為止。 
  6. 參數(shù): 
  7.   str:字符串首地址 
  8.   format:字符串格式,用法和printf()一樣 
  9. 返回值: 
  10.   成功:實(shí)際格式化的字符個(gè)數(shù) 
  11.   失敗: - 1 

示例代碼如下:

  1. char dst[100] = { 0 }; 
  2.   int a = 10; 
  3.   char src[] = "hello"
  4.   int len = sprintf(dst, "a=%d, src=%s", a, src); 
  5.   printf("dst: %s\n", dst);  輸出 a=10,src=hello 
  6.   printf("len = %d\n", len);  輸出14 

下面再介紹幾個(gè)字符串操作函數(shù),但這幾個(gè)使用頻率比較?。?/p>

8) sscanf()

  1. #include <stdio.h> 
  2. int sscanf(const char *str, const char *format, ...); 
  3. 功能:從str指定的字符串讀取數(shù)據(jù), 
  4.   并根據(jù)參數(shù)format字符串來轉(zhuǎn)換并格式化數(shù)據(jù)。 
  5. 參數(shù): 
  6.   str:指定的字符串首地址 
  7.   format:字符串格式,用法和scanf()一樣 
  8. 返回值: 
  9.   成功:參數(shù)數(shù)目,成功轉(zhuǎn)換的值的個(gè)數(shù) 
  10.   失?。?nbsp;- 1 

示例代碼:

  1. char src[] = "a=10, b=20"
  2.   int a; 
  3.   int b; 
  4.   sscanf(src, "a=%d,  b=%d", &a, &b); 
  5.   printf("a:%d, b:%d\n", a, b); 
  6.   輸出:a:20,b:20 

sscanf與scanf類似,都是用于輸入的,只是后者以屏幕(stdin)為輸入源,前者以固定字符串為輸入源。

9) strchr()

  1. #include <string.h> 
  2. char *strchr(const char *s, char c); 
  3. 功能:在字符串s中查找字母c出現(xiàn)的位置 
  4. 參數(shù): 
  5.   s:字符串首地址 
  6.   c:匹配字母(字符) 
  7. 返回值: 
  8.   成功:返回第一次出現(xiàn)的c地址(注意是地址,不是字符數(shù)組索引) 
  9.   失敗:NULL 

示例代碼:

  1. char src[] = "ddda123abcd"
  2. char *p = strchr(src, 'a'); 
  3. printf("p = %s\n", p); 
  4. 輸出:p=a123abcd 

10)strstr()

  1. #include <string.h> 
  2. char *strstr(const char *haystack, const char *needle); 
  3. 功能:在字符串haystack中查找字符串needle出現(xiàn)的位置 
  4. 參數(shù): 
  5.   haystack:源字符串首地址 
  6.   needle:匹配字符串首地址 
  7. 返回值: 
  8.   成功:返回第一次出現(xiàn)的needle地址 
  9.   失?。?span id="k6zqhab033oa" class="op">NULL 

這個(gè)函數(shù)與上一個(gè) strchr 功能類似,只不過查找的內(nèi)容是字符串,而非字單個(gè)字符。

11) strtok()

  1. #include <string.h> 
  2. char *strtok(char *str, const char *delim); 
  3. 功能:將字符串分割成一個(gè)個(gè)片段,  
  4.       當(dāng)strtok()在參數(shù)str的字符串中發(fā)現(xiàn)參數(shù)delim中包含的分割字符時(shí),  
  5.       則會將該字符改為\0 字符,當(dāng)連續(xù)出現(xiàn)多個(gè)時(shí)只替換第一個(gè)為\0, 
  6.       該函數(shù)會破壞原有字符串。 
  7. 參數(shù): 
  8.   str:指向欲分割的字符串 
  9.   delim:為分割字符串中包含的所有字符 
  10. 返回值: 
  11.   成功:分割后字符串首地址 
  12.   失?。?span id="k6zqhab033oa" class="op">NULL 

示例代碼:

  1. char a[100] = "www.baidu.com"
  2. char *p = strtok(a, "."); 
  3. while (p != NULL
  4. {   
  5.   printf("%s\n", p);   
  6.   p = strtok(NULL"."); 
  7. 輸出:www baidu com 

以上,就是本文的全部內(nèi)容了。

責(zé)任編輯:武曉燕 來源: 編碼珠璣
相關(guān)推薦

2011-07-15 11:07:41

C語言字符串函數(shù)

2011-07-15 12:41:53

C語言

2009-07-15 17:20:45

Jython字符串

2010-09-06 17:30:46

SQL函數(shù)

2009-08-24 13:04:44

操作步驟C#字符串

2009-08-06 16:01:09

C#字符串函數(shù)大全

2011-03-30 11:01:13

C語言隨機(jī)

2010-01-25 17:05:37

C++語言

2010-01-18 13:54:28

函數(shù)

2009-09-02 13:41:57

C#字符串操作

2010-03-11 19:16:32

Python語言

2010-09-09 11:48:00

SQL函數(shù)字符串

2015-04-08 10:27:43

JavaScript字符串操作函數(shù)

2014-01-02 16:14:10

PostgreSQL字符串

2022-11-10 07:43:45

2009-09-01 17:58:55

C#截取字符串

2009-09-01 17:41:53

C#截取字符串函數(shù)

2023-03-21 15:27:00

RedisC語言字符串

2024-02-20 20:12:09

C語言字符串Redis

2010-01-11 15:29:13

引用C++語言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號