c語言中的字符串操作函數

2022-01-09 編碼珠璣

收錄於話題 #編程珠璣 11個

我們知道,c/c++之所以使用起來靈活,很大原因歸因於它能夠它對能夠對內存的直接操作,所以本文我主要講述一下c中的字符串操作函數。

一,常量指針與指針常量

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

int a = 100;const int * p = &a;  int const * p = &a;  int * const p = &a;  

那麼究竟如何區分常量指針與指針常量呢,這裡邊有個技巧,上篇文章中我忘記給大家說了:

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

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

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

第二行代碼,常量指針:

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

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

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

char str1[] = "hello world";  char* str2 = "hello world";  

那麼這兩種在使用起來究竟有什麼區別呢?答案是第一行定以後,作業系統給它分配的是棧區內存,而第二行通過指針形式來定義字符串的話,它分配的內存區在數據的常量區,意味著它的值是不可更改的:

str1[0] = 'm';  //正確,字符數組可以修改str2[0] = 'm'; //錯誤,常量區不可修改

所以,在常量區,如果我們兩個內容相同但變量不同的指針變量,其實它們指向的是同一塊內存:

char* str1 = "hello world";  char* str2 = "hello world";  printf("%p\n",str1);printf("%p\n",str2);

上面兩行代碼中,我們將str1與str2指向的內存地址分別列印出來,發現他們的值是一樣的,為什麼呢,這是因為常量區內存的值是只讀的,我們即便聲明兩個不同的變量,只要他們的值是相同的,那麼兩個變量指向的就是同一塊內存區域。

這裡值得注意的是,在c++中,字符串指針與c語言中稍有區別,c++中直接將字符串指針做了增強處理,因為c++中規定字符串指針必須用const修飾,例如在c++中這樣定義,編譯器會直接報錯:

char* str = "hello world";  const char * str = "hello world";

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

char str[] = "hello world";  char* str = "hello world";

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

二,字符串長度問題

我們知道c語言中的字符串是以 '\0' 為結尾的,也就是說你在聲明一個字符串的時候,系統會自動為你的結尾添加上一個以 '\0' 為結尾的結束字符,而且,printf 在每列印一個字符就會檢查當前字符是否為 『\0』 ,直到遇到 '\0' 立馬停止。這裡最容易混淆的的是字符串的長度,我們來看下面兩行代碼:

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

char str1[] = "hello";char* str2 = "hello";printf("%d\n", sizeof(str1));  printf("%d\n", sizeof(str2));  

那麼為什麼在使用 sizeof 計算字符串長度,兩者計算出來的結果不一樣呢,而且第一行長度還不是我們想要的,不應該是 5 才對嗎?這是因為在聲明一個字符串的時候,系統會自動為你的結尾添加上一個以 '\0' 為結尾的結束字符,內存模型如下:

所以,對於上面兩行代碼,實際上它們的長度都為 6 才對。那為什麼第二行輸出卻為 4 呢,這是因為第二行我們定義的是一個字符串指針,它指向一個常量區的字符串,而 sizeof 操作符操作這個指針的時候,實際上計算的是這個指針的字節長度,而一個指針在x86系統下佔有長度為 4 字節,在x64環境下佔有長度為 8 字節,所以,在實際上我們計算字符串長度的時候,一般會用 strlen() 這個函數,但是要注意,strlen 計算字符串也是以 '\0' 為結束的,也就是說,strlen() 函數會不斷判斷當前字符是否為 '\0',如果是的話,立馬結束,這個特點與printf函數一樣,兩者都是碰到 '\0' 就立馬結束:

char str1[] = "abc";char str2[] =  {'a', '\0', 'c'};char str3[] =  {'a', 'b', 'c', '\0'};char* str4 = "abc";printf("%d\n", strlen(str1));  printf("%d\n", strlen(str2));  printf("%d\n", strlen(str3));  printf("%d\n", strlen(str4));  

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

三,c語言中的字符串拷貝函數


1) strcpy()

#include <string.h>char *strcpy(char *dest, const char *src);參數: dest:目的字符串首地址 src:源字符首地返回值: 成功:返回dest字符串的首地址  失敗:NULL

示意代碼如下:

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

內存模型如下:

由於是逐個拷貝,意味著哪怕在字符串的中間遇到了 '\0' 字符,也會結束拷貝。

這裡邊要注意兩個問題:第一,必須保證 dest 所指向的內存空間足夠大,否則可能會造成緩衝溢出的錯誤;第二,由於本身strcpy函數是一個非安全函數,所以編譯器會彈出警告,要想忽略,請在程序最開頭添加宏定義代碼:

#define _CRT_SECURE_NO_WARNINGS

2), strncpy()

#include <string.h>char *strncpy(char *dest, const char *src, size_t n);功能: 把src指向字符串的前n個字符複製到dest所指向的空間中, 是否拷貝結束符看指定的長度是否包含'\0'。參數: dest:目的字符串首地址 src:源字符首地址 n:指定需要拷貝字符串個數返回值: 成功:返回dest字符串的首地址  失敗:NULL

這個函數與strcpy類似,這裡不再累贅。

3), strcat()

#include <string.h>char *strcat(char *dest, const char *src);功能:將src字符串連接到dest的尾部,『\0』也會追加過去參數: dest:目的字符串首地址 src:源字符首地址返回值: 成功:返回dest字符串的首地址  失敗:NULL

這是一個字符串追加函數,將 src 指向的字符串追加到 dest 指向的字符串後面,同樣,結束符 '\0' 也會追加過去:

#define _CRT_SECURE_NO_WARNINGS #include <string.h> char str[] = "123"; char str1[] = "hello"; char* mystr = strcat(str, str1); printf("%s\n%p", mystr, mystr);   

但是同樣注意的是,目標字符串 dest 要有足夠大的緩衝區來接收,否則會報錯,內存模型如下:

4), strncat()

#include <string.h>char *strncat(char *dest, const char *src, size_t n);功能:將src字符串前n個字符連接到dest的尾部,『\0』也會追加過去參數:  dest:目的字符串首地址  src:源字符首地址  n:指定需要追加字符串個數返回值:  成功:返回dest字符串的首地址  失敗:NULL

這個函數與strcat類似,只不過指定了追加的數量。

5), strcmp()

#include <string.h>char *strcat(char *dest, const char *src);功能:將src字符串連接到dest的尾部,『\0』也會追加過去參數:  dest:目的字符串首地址  src:源字符首地址返回值:  成功:返回dest字符串的首地址  失敗:NULL

作用是對兩個字符串的ASCII碼進行比較,輸出不同結果,經常用於判斷兩個字符串是否相等,示例代碼如下:

char *str1 = "hello world";char *str2 = "hello mike";
if (strcmp(str1, str2) == 0){ printf("str1==str2\n");}else if (strcmp(str1, str2) > 0){ printf("str1>str2\n");} else{ printf("str1<str2\n");}

6), strncmp()

#include <string.h>int strncmp(const char *s1, const char *s2, size_t n);功能:比較 s1 和 s2 前n個字符的大小,比較的是字符ASCII碼大小。參數: s1:字符串1首地址 s2:字符串2首地址 n:指定比較字符串的數量返回值: 相等:0 大於:> 0  小於: < 0

這個函數作用也是與strcmp類似,不再累贅。

7), sprintf()

#include <stdio.h>int sprintf(char *str, const char *format, ...);功能:根據參數format字符串來轉換並格式化數據,      然後將結果輸出到str指定的空間中,      直到出現字符串結束符 '\0' 為止。參數: str:字符串首地址 format:字符串格式,用法和printf()一樣返回值: 成功:實際格式化的字符個數  失敗: - 1

示例代碼如下:

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

下面再介紹幾個字符串操作函數,但這幾個使用頻率比較小:

8) sscanf()

#include <stdio.h>int sscanf(const char *str, const char *format, ...);功能:從str指定的字符串讀取數據, 並根據參數format字符串來轉換並格式化數據。參數: str:指定的字符串首地址 format:字符串格式,用法和scanf()一樣返回值: 成功:參數數目,成功轉換的值的個數  失敗: - 1

示例代碼:

char src[] = "a=10, b=20"; int a; int b; sscanf(src, "a=%d, b=%d", &a, &b); printf("a:%d, b:%d\n", a, b); 輸出:a:20,b:20

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

9) strchr()

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

示例代碼:

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

10), strstr()

#include <string.h>char *strstr(const char *haystack, const char *needle);功能:在字符串haystack中查找字符串needle出現的位置參數: haystack:源字符串首地址 needle:匹配字符串首地址返回值: 成功:返回第一次出現的needle地址  失敗:NULL

這個函數與上一個 strchr 功能類似,只不過查找的內容是字符串,而非字單個字符。

11) strtok()

#include <string.h>char *strtok(char *str, const char *delim);功能:將字符串分割成一個個片段,  當strtok()在參數str的字符串中發現參數delim中包含的分割字符時,       則會將該字符改為\0 字符,當連續出現多個時只替換第一個為\0,      該函數會破壞原有字符串。參數: str:指向欲分割的字符串 delim:為分割字符串中包含的所有字符返回值: 成功:分割後字符串首地址  失敗:NULL

示例代碼:

char a[100] = "www.baidu.com";char *p = strtok(a, ".");while (p != NULL){    printf("%s\n", p);    p = strtok(NULL, ".");}輸出:www baidu com

以上,就是本文的全部內容了。

相關焦點

  • C語言中的字符串操作函數
    我們知道,c/c++之所以使用起來靈活,很大原因歸因於它能夠它對能夠對內存的直接操作,所以本文我主要講述一下c中的字符串操作函數。我們再回到本節的字符串問題上,在講述字符串拷貝函數前,我們再來回憶一下c語言中的字符串。
  • C語言字符串操作總結
    * 具有指定長度的字符串處理函數在已處理的字符串之後填補零結尾符2)字符串到數值類型的轉換 strtod(p, ppend) 從字符串 p 中轉換 double 類型數值,並將後續的字符串指針存儲到 ppend 指向的 char* 類型存儲。
  • C 語言中的 字符串
    字符串常量是一對雙撇號括起來的字符序列,例如:"helloworld"、"12345"、""(一個空字符串)在C語言中
  • c語言字符串比較函數詳解
    操作成功則返回buf中首次出現c的位置指針, 否則返回NULL.如果字符c被複製, 函數返回這個字符後面緊挨一個字符位置的指針. 否則返回NULL.size_t strlen(const char *string);獲取字符串長度, 字符串結束符NULL不計算在內.沒有返回值指示操作錯誤.
  • C字符串處理函數
    C字符串處理函數,考試時一般需要自己編寫,不能直接調用庫函數。對於一下字符串處理函數,嘗試編寫自己的函數。
  • C語言字符串處理函數之字符串轉換、查詢函數
    介紹完字符串整體操作函數,就該到字符串查詢函數和字符串轉換函數了,至於一些字符串轉換函數,如atoi(),atof(),strtod(),strtol(),tolower(),toupper()等,以後有時間再整理整理。
  • C語言字符串詳解
    ,C語言中的字符串都以字符串常量的形式出現或存儲在字符數組中。同時,C 語言提供了一系列庫函數來對操作字符串,這些庫函數都包含在頭文件 string.h 中。一、字符串常量和字符數組1.1、什麼是字符串常量C 語言雖然沒有字符串類型,但是 C語言提是存在字符串這個概念的,也就是字符串常量:以 NUL 字節結尾的 0 個或多個字符組成的序列。
  • C語言 -- 字符串詳解
    ,C語言中的字符串都以字符串常量的形式出現或存儲在字符數組中。同時,C 語言提供了一系列庫函數來對操作字符串,這些庫函數都包含在頭文件 string.h 中。一、字符串常量和字符數組1.1、什麼是字符串常量C 語言雖然沒有字符串類型,但是 C語言提是存在字符串這個概念的,也就是字符串常量:以 NUL 字節結尾的 0 個或多個字符組成的序列。
  • 【自學C語言】書筆記I 20b 字符串比較函數
    而這裡需要注意的是:            因為返回值不是小於0,就是等於0,或者大於0,所以通過判斷是小於0,還是大於0,或者等於0,就可以對字符串進行相對應的操作。    運行結果:    注意:        1)函數在比較過程中,要區分字母大小寫。
  • 常見的C語言字符串操作
    #整型轉字符串實現邏輯,每個整數看其轉換進位,從個位到十位百位都可以通過%操作加上/操作獲得,再用一個字符數組保存0-F。用個位數對應值轉為字符,注意轉換出的字符串是反向的,還要考慮傳入的若是負數如何處理,再用翻轉字符串完成最後整個操作下面這段代碼需要好好研究一下,最好自己運行試試。
  • C/C++字符串操作的全面總結
    總結一下構建string對象方法、修改string對象的方法、string類型的操作函數、string類型的查找、string對象的比較。首先,為了在我們的程序中使用string類型,我們必須包含頭文件 。如下: 這樣我們就聲明了一個字符串變量,但既然是一個類,就有構造函數和析構函數。
  • C語言中常用的6個字符串處理函數
    01.C語言基礎-數據類型02.C語言中算法的基本特性和表達方式03.C語言中的輸入輸出函數04.C語言基礎-循環控制語句05.C語言基礎-條件控制語句06.C語言基礎-控制語句示例07.C語言數組- 一維數組08.C語言數組- 二維數組09.C語言數組-字符數組
  • C語言字符串處理函數詳解
    (1)memchrvoid *memchr(const void *str, int c, size_t n)參數列表: str:字符串指向的內存塊 ch:待查找字符 n:指定str中的前n個字符 返回值:   返回一個指向匹配字節的指針   如果在給定的內存區域未出現字符,則返回NULL(2
  • 單片機c語言字符串操作
    這個函數也可以整形、浮點型轉字符串sprintf(dest,"%f",3.1415926f);dest 就是「3.1415926」sprintf(dest,"現在的時間是%s,請注意","2014-04-09 11:27:21"); 後面這個字符串也可以換成變量dest的值是 "現在的時間是2014-04-09 11:27:21,
  • 常見的C語言字符串操作
    #整型轉字符串實現邏輯,每個整數看其轉換進位,從個位到十位百位都可以通過%操作加上/操作獲得,再用一個字符數組保存0-F。用個位數對應值轉為字符,注意轉換出的字符串是反向的,還要考慮傳入的若是負數如何處理,再用翻轉字符串完成最後整個操作下面這段代碼需要好好研究一下,最好自己運行試試。
  • 【C語言-40】字符串處理函數
    這一節中我們來討論C語言自帶的字符串處理函數。與printf不同,這些函數不在之前熟悉的頭文件stdio.h中。而是在字符串專用的頭文件string.h中。#include <string.h>接下來,我們將討論一些常用的字符串處理函數的使用。strlen函數可以獲取字符數組中的字符串長度。
  • 面試常見的C語言字符串操作
    程序輸出 #整型轉字符串 實現邏輯,每個整數看其轉換進位,從個位到十位百位都可以通過%操作加上/操作獲得,再用一個字符數組保存0-F。
  • C語言編程技巧:如何在函數中正確返回字符串的指針
    問題提出在C語言編程中,我們經常會遇到這種情況,在某個函數中經過算法處理以後得到一個字符串類型的結果,可能需要將這個字符串以指針的形式進行返回,那麼如何在函數中正確返回該字符串的內容呢?函數中返回字符串指針的正確方法那麼,如何在函數中正確返回字符串的內容呢?
  • 快速上手系列-C語言之字符串處理函數(一)
    C語言中常用的字符串操作函數,有比如計算字符串長度、字符串拷貝,字符串比較等這樣的整體操作函數,有字符串查詢函數,也有字符串轉換函數等等,這裡先介紹字符串整體操作函數。字符串整體操作函數實際編程中,經常遇到對字符串整體的控制等操作,比如長度測量函數strlen(),字符串拷貝函數strcpy()/strncpy(),字符串比較函數 strcmp()/strncmp(),字符串連接函數strcat()/strncat()等,這些函數是非常有用的。
  • 談談Go語言字符串
    字符串是一種特別重要的類型, 可以說整個世界都是建立在字符串處理基礎之上的, 甚至有很多專門針對字符串處理設計的程式語言(比如perl). 因為字符串處理非常重要, Go語言將字符串作為值以簡化使用, 同時標準庫提供了strings/fmt/strconv/regexp/template等諸多包用於協助處理字符串.1.