暑期自學嵌入式——Day05補充(C語言階段)

接續上文:暑期自學嵌入式——Day05(C語言階段)-CSDN博客

主頁點關注不迷路喲。你的點贊、收藏,一鍵三連,是我持續更新的動力喲!!!

主頁:

一位搞嵌入式的 genius-CSDN博客https://blog.csdn.net/m0_73589512?spm=1010.2135.3001.5343

Day05(補充)

字符數組和字符串:字符串逆序輸出詳解

一、字符串逆序輸出的實現思路與方法

1. 兩種核心實現思路
實現方式核心邏輯優缺點分析
僅逆序顯示(不修改原串)不改變字符串存儲順序,僅從最后一個有效字符倒序打印到第一個字符優點:簡單直接,不破壞原數據;缺點:未真正修改字符串(僅輸出層面逆序)
原地逆序(修改原串后顯示)通過交換字符位置,將原字符串改為逆序(如 "abc"→"cba"),再正常打印優點:真正實現字符串逆序存儲;缺點:需修改原數據,邏輯稍復雜
2. 基礎實現:僅逆序顯示(不修改原串)
(1)核心步驟
  1. 獲取輸入:用getsscanf讀取字符串(gets支持空格,scanf遇空格停止)。

  2. 計算有效長度:用strlen獲取字符串實際長度(不含'\0')。

  3. 倒序循環輸出:從len-1(最后一個字符下標)循環到0,逐個輸出字符。

(2)示例代碼
#include <stdio.h>
#include <string.h>
#define N 20 ?// 數組大小
?
int main() {char arr[N];printf("Please input a string: ");gets(arr); ?// 獲取輸入(支持空格,如"hello world")
?int len = strlen(arr); ?// 計算有效長度(不含'\0')printf("逆序輸出:");// 從最后一個字符(len-1)倒序輸出到第一個(0)for (int i = len - 1; i >= 0; i--) {putchar(arr[i]); ?// 逐個輸出字符}putchar('\n'); ?// 手動換行return 0;
}
(3)關鍵技巧
  • strlen vs sizeof

    • strlen(arr):返回字符串有效長度(僅'\0'之前的字符數,如 "hello" 返回 5)。

    • sizeof(arr):返回數組總空間(定義為N=20,則返回 20,包含未使用的空間)。

    • 必須用strlen:避免打印未初始化的垃圾字符(如數組定義為 20,但輸入僅 5 個字符)。

3. 進階實現:原地逆序(修改原串)
(1)核心算法:雙指針法
  • 指針定義:

    • i:從頭部開始(初始i=0)。

    • j:從尾部開始(初始j = strlen(arr) - 1)。

  • 操作邏輯:交換arr[i]arr[j],然后i++j--,直到i >= j(兩指針相遇,所有字符交換完成)。

(2)示例代碼
#include <stdio.h>
#include <string.h>
#define N 20
?
int main() {char arr[N];printf("Please input a string: ");gets(arr);int len = strlen(arr);
?// 雙指針交換(原地逆序)int i = 0; ? ? ? ? ? ? ? ? ?// 頭指針int j = len - 1; ? ? ? ? ? ?// 尾指針while (i < j) { ? ? ? ? ? ? // 兩指針未相遇時循環char temp = arr[i]; ? ? // 臨時變量輔助交換arr[i] = arr[j];arr[j] = temp;i++; ? ? ? ? ? ? ? ? ? ?// 頭指針后移j--; ? ? ? ? ? ? ? ? ? ?// 尾指針前移}
?// 輸出逆序后的字符串printf("逆序后的字符串:%s\n", arr); ?// 此時arr已變為逆序return 0;
}
(3)過程演示(以輸入 "apple" 為例)
步驟ij交換前交換后操作說明
104"apple""eppla"交換a[0]('a')和a[4]('e')
213"eppla""eplpa"交換a[1]('p')和a[3]('l')
322"eplpa"(停止)i >= j,循環終止
最終結果---"elppa"完成逆序

二、輸入函數的選擇與注意事項

1. getsscanffgets對比
函數特點安全隱患 / 注意事項
gets(arr)讀取整行字符串(支持空格),直到換行符為止(自動忽略換行符,添加'\0'無長度限制,若輸入超過數組大小會導致越界(已棄用,編譯器會警告)
scanf("%s", arr)遇空格、換行等分隔符停止讀取,自動添加'\0'無法讀取帶空格的字符串(如 "hello world" 只能讀到 "hello")
fgets(arr, N, stdin)讀取最多N-1個字符(預留'\0'),保留換行符,更安全需手動處理換行符(如arr[strcspn(arr, "\n")] = '\0'去除換行);推薦使用
2. 輸入函數使用建議
  • 讀取帶空格的字符串:優先用fgets(安全),避免gets(有溢出風險)。

  • 讀取無空格的字符串scanf("%s", arr)更簡潔(注意限制輸入長度,如scanf("%19s", arr),數組大小為 20 時)。

  • 示例(fgets替代gets):

    #include <stdio.h>
    #include <string.h>
    ?
    int main() {char arr[20];printf("請輸入字符串(支持空格):");fgets(arr, 20, stdin); ?// 最多讀19個字符(留1個給'\0')// 去除fgets保留的換行符(若有)arr[strcspn(arr, "\n")] = '\0'; ?// strcspn計算到'\n'的長度
    ?printf("你輸入的是:%s\n", arr);return 0;
    }

三、知識小結

知識點核心內容考試重點 / 易混淆點難度系數
逆序顯示(方法 1)倒序循環輸出(i從len-1到0),不修改原串;依賴strlen獲取有效長度sizeof(總空間)與strlen(有效長度)的區別;避免打印未初始化字符???
原地逆序(方法 2)雙指針法交換字符(i=0j=len-1交換,直到i>=j);需臨時變量輔助循環終止條件(i < j而非i <= j,避免重復交換);奇 / 偶長度字符串的處理(自動兼容)????
輸入函數對比gets支持空格但不安全;scanf遇空格停止;fgets安全且支持空格gets的溢出風險;fgets保留換行符的處理方法??
字符串長度計算strlen返回有效長度(不含'\0'),需包含<string.h>;也可手動循環計算手動計算長度的循環邏輯(while(arr[i] != '\0') i++??
數組越界預防輸入時限制長度(如fgetsN參數、scanf%19s);初始化數組避免垃圾值gets無長度限制導致的溢出;未初始化數組的隨機值打印???

四、編程技巧

  1. 調試技巧: 逆序邏輯出錯時,可打印中間過程(如雙指針交換時的ij值和數組內容):

    while (i < j) {printf("交換前:i=%d, j=%d, arr=%s\n", i, j, arr);// 交換代碼printf("交換后:i=%d, j=%d, arr=%s\n", i, j, arr);
    }
  2. 邊界條件處理: 考慮特殊輸入(如空字符串""、單字符"a"),確保程序不崩潰:

    • 空字符串:strlen返回 0,循環不執行(正確)。

    • 單字符:i=0j=0i < j不成立,循環不執行(無需交換,正確)。

  3. 函數封裝: 將逆序邏輯封裝為函數,提高復用性:

    // 原地逆序函數
    void reverseString(char* arr) {int len = strlen(arr);int i = 0, j = len - 1;while (i < j) {char temp = arr[i];arr[i] = arr[j];arr[j] = temp;i++;j--;}
    }

    通過以上內容,可掌握字符串逆序的兩種核心方法,理解輸入函數的特性及安全用法,同時規避數組越界等常見問題。

字符串函數:從基礎到應用

一、字符串函數概述

1. 核心概念
  • 定義:C 語言標準庫(string.h頭文件)中封裝的專用函數,用于簡化字符串操作(如計算長度、拷貝、比較等)。

  • 重要性:字符串是編程中最常用的數據形式之一,直接手寫邏輯(如遍歷計算長度)低效且易出錯,函數封裝可大幅提升開發效率。

  • 使用前提:所有字符串函數必須通過 #include <string.h> 聲明頭文件,否則編譯器會報錯(“未聲明的函數”)。

二、常用字符串函數詳解

1. 字符串長度函數 strlen
(1)功能與原型
  • 功能:計算字符串中 有效字符的個數(從首字符開始,直到遇到 '\0' 為止,不含 '\0')。

  • 函數原型:

    size_t strlen(const char *s); ?// size_t是無符號整數類型(unsigned int)
    • 參數 s:字符串的首地址(字符數組名或字符串常量)。

    • 返回值:有效字符數(無符號整數,如 "abc" 返回 3)。

(2)應用示例與解析
基礎示例
#include <stdio.h>
#include <string.h>
?
int main() {// 示例1:顯式包含'\0'的字符數組char s1[10] = {'A', '\0', 'B', 'C', '\0', 'D'};printf("s1長度:%zu\n", strlen(s1)); ?// 結果:1(遇到第一個'\0'即停止)
?// 示例2:字符串常量初始化(隱含'\0')char s2[] = "maker"; ?// 存儲為'm','a','k','e','r','\0'printf("s2長度:%zu\n", strlen(s2)); ?// 結果:5(不含'\0')return 0;
}
轉義字符處理

轉義字符(如 \t\n)雖由多個字符組成(反斜杠 + 字母),但在字符串中視為 單個字符strlen 計為 1。

// 示例:轉義字符的長度計算
char s3[] = "\tab\n\v\w\e"; ?// 包含\t、\a、\n、\v、\w、\e(共6個字符)
printf("s3長度:%zu\n", strlen(s3)); ?// 結果:6
特殊編碼(十六進制 / 八進制)

字符串中可通過 \xhh(十六進制)或 \ooo(八進制)表示字符,strlen 計為 1 個字符。

// 示例:十六進制和八進制編碼
char s4[] = "\x69\141"; ?// \x69是十六進制69(ASCII碼105,對應'i');\141是八進制141(ASCII碼97,對應'a')
printf("s4內容:%s\n", s4); ?// 輸出"ia"
printf("s4長度:%zu\n", strlen(s4)); ?// 結果:2
(3)strlensizeof 的核心區別
對比項strlen(s)sizeof(s)
本質函數,計算 有效字符數(不含 '\0'運算符,計算 變量 / 類型的總內存字節數(含 '\0' 及未使用空間)
示例(char s[] = "maker"返回 5('m','a','k','e','r'返回 6(5 個字符 + 1 個 '\0'
示例(char s[10] = "maker"返回 5(有效字符不變)返回 10(數組總空間固定為 10 字節)
計算時機運行時計算(遍歷字符串直到 '\0'編譯時計算(已知類型 / 數組大小)
2. 其他重要字符串函數(基礎認知)
函數功能原型示例關鍵注意事項
strcpy將源字符串拷貝到目標數組(包括 '\0'char* strcpy(char *dest, const char *src);目標數組需足夠大(否則越界);源字符串必須以 '\0' 結尾
strcat將源字符串連接到目標字符串末尾(覆蓋目標原 '\0',添加新 '\0'char* strcat(char *dest, const char *src);目標數組需預留足夠空間;源和目標不能重疊(如 strcat(s, s) 會出錯)
strcmp按 ASCII 碼比較兩個字符串(逐個字符對比,直到不同或 '\0'int strcmp(const char *s1, const char *s2);返回值:s1 > s2 為正,s1 < s2 為負,相等為 0;不能用 == 直接比較字符串

三、知識小結

知識點核心內容考試重點 / 易混淆點難度系數
字符串函數基礎需包含 <string.h>;封裝高頻操作(如 strlen 計算長度)忘記包含頭文件導致的編譯錯誤;函數參數類型(const char* 表示只讀)??
strlen 函數計算有效字符數(不含 '\0');轉義字符、特殊編碼均計為 1 個字符sizeof 的區別(運行時 vs 編譯時;有效字符 vs 總內存);遇到第一個 '\0' 即停止???
轉義字符與特殊編碼\t\n 等轉義字符計為 1;\x69(十六進制)、\141(八進制)對應單個字符八進制 / 十六進制編碼的轉換(如 \141 對應 'a');轉義字符的計數規則????
其他函數(strcpy等)strcpy 拷貝、strcat 連接、strcmp 比較;均依賴 '\0' 作為終止標志strcpy 的越界風險;strcmp 的返回值判斷(非 0 即不等,正 / 負表示大小)???

四、編程建議

  1. strlen 使用注意

    • 僅用于以 '\0' 結尾的字符串(字符數組無 '\0' 時,strlen 會越界讀取,結果隨機)。

    • 返回值是 size_t(無符號),避免與有符號整數比較(如 if (strlen(s) >= -1) 永遠成立,因無符號不會為負)。

  2. sizeofstrlen 對比記憶

    • 記口訣:strlen 算 “內容長度”(有效字符),sizeof 算 “房子大小”(總內存)。

    • 示例:char s[10] = "abc"strlen=3(內容),sizeof=10(房子)。

  3. 函數學習方法: 先掌握 strlen 等基礎函數的用法和原理,遇到未知函數(如 strstr 查找子串)時,學會查閱 C 語言手冊(如cplusplus.com),重點關注功能、參數、返回值和注意事項。

通過以上內容,可掌握 strlen 的核心用法及字符串函數的基礎認知,明確 strlensizeof 的關鍵區別,為后續學習字符串拷貝、比較等函數奠定基礎。

字符串函數:字符串拷貝函數strcpy詳解

一、strcpy函數的基本介紹

1. 函數格式與核心功能
  • 函數原型:

    char *strcpy(char *dest, const char *src);
  • 核心功能:將源字符串(src)完整拷貝到目標字符數組(dest)中,包括字符串結束符'\0',最終目標數組成為源字符串的副本。

  • 參數與返回值:

    • dest:目標字符數組(必須是可修改的左值,如char arr[20],不能是字符串常量)。

    • src:源字符串(可以是字符數組或字符串常量,如"hello",必須以'\0'結尾)。

    • 返回值:目標數組dest的首地址(方便鏈式調用,如printf("%s", strcpy(dest, src)))。

2. 關鍵使用規則(必須遵守)
  1. 目標數組空間必須足夠大: 需能容納源字符串的所有字符(包括'\0'),否則會導致緩沖區溢出(覆蓋相鄰內存,程序可能崩潰或輸出亂碼)。

    • 示例:源字符串"hello"(長度 5,含'\0'共 6 字節),目標數組至少需 6 字節(如char dest[6])。

  2. 源字符串必須以'\0'結尾strcpy通過'\0'判斷拷貝結束,若源字符串無'\0',會越界拷貝(直到意外遇到'\0')。

  3. 源和目標不能重疊: 如strcpy(arr+2, arr)(目標是源的一部分)會導致拷貝結果異常(標準未定義行為)。

  4. 數組名不能直接賦值: 錯誤寫法:dest = src;(數組名是地址常量,不能被修改),必須用strcpy逐字符拷貝。

二、strcpy函數的使用示例與原理

1. 基礎使用示例
#include <stdio.h>
#include <string.h>
?
int main() {char src[] = "hello world"; ?// 源字符串(含'\0'共12字節)char dest[20]; ?// 目標數組(空間足夠大)
?// 拷貝src到deststrcpy(dest, src);
?// 輸出結果(兩者內容相同)printf("源字符串:%s(地址:%p)\n", src, src);printf("目標數組:%s(地址:%p)\n", dest, dest);return 0;
}
  • 輸出結果: 源字符串和目標數組均輸出hello world,證明拷貝完整(包括'\0')。

2. strcpy的手動實現(理解底層原理)

strcpy本質是通過循環逐字符拷貝,直到遇到源字符串的'\0'并拷貝它。

// 手動實現strcpy功能(簡化版)
char* my_strcpy(char* dest, const char* src) {// 保存目標首地址(用于返回)char* original_dest = dest;
?// 逐字符拷貝(包括'\0')while (*src != '\0') {*dest = *src; ?// 拷貝當前字符dest++; ? ? ? ?// 目標指針后移src++; ? ? ? ? // 源指針后移}*dest = '\0'; ?// 拷貝結束符(關鍵!)
?return original_dest; ?// 返回目標首地址
}
  • 核心邏輯: 循環拷貝每個字符(*src)到目標地址(*dest),直到*src'\0',最后單獨拷貝'\0'(確保目標數組以'\0'結尾)。

3. 常見錯誤與規避
(1)目標數組空間不足(高危)
char src[] = "this is a long string"; ?// 長度21(含'\0'共22字節)
char dest[10]; ?// 空間不足(僅10字節)
strcpy(dest, src); ?// 緩沖區溢出!覆蓋相鄰內存,程序可能崩潰
  • 規避方法:

    拷貝前檢查目標數組長度是否 ≥ 源字符串長度 + 1(

    strlen(src)+1

    ):

    if (sizeof(dest) >= strlen(src) + 1) {strcpy(dest, src); ?// 安全拷貝
    } else {printf("目標空間不足!\n");
    }
(2)忘記拷貝'\0'(手動實現時)
// 錯誤示例:循環條件遺漏'\0'
void bad_copy(char* dest, const char* src) {int i = 0;while (src[i] != '\0') { ?// 僅拷貝到'\0'前的字符dest[i] = src[i];i++;}// 未拷貝'\0',dest不是合法字符串
  • 后果:目標數組無'\0',用%s輸出時會越界讀取(亂碼)。

  • 正確做法:循環結束后手動添加'\0':

    dest[i] = '\0'; ?// 必須添加結束符
(3)直接賦值數組名(語法錯誤)
char dest[20], src[] = "hello";
dest = src; ?// 錯誤!數組名是地址常量,不能被賦值
  • 原因:數組名代表首地址(常量),不能作為左值修改,必須通過strcpy逐字符拷貝。

二、strcpy函數的總結與對比

核心要點說明易錯點提醒
拷貝范圍src[0]src[n]nstrlen(src)),包括src[n](即'\0'手動實現時需確保'\0'被拷貝(否則目標數組不是合法字符串)
目標數組要求必須可修改(非字符串常量)、空間足夠(≥strlen(src)+1字符串常量(如"test")不能作為destconst類型不可修改)
與直接賦值的區別strcpy是逐字符拷貝內容,dest = src是地址賦值(語法錯誤)數組名是常量,不能直接賦值,必須用strcpy
安全性本身不檢查空間(需程序員手動確保),存在溢出風險實際開發中可使用strncpy(指定最大拷貝長度)替代,更安全

三、知識小結

知識點核心內容考試重點 / 易混淆點難度系數
strcpy 基本用法格式:strcpy(dest, src);拷貝源字符串(含'\0')到目標數組;返回dest首地址參數順序(dest在前,src在后);必須包含'\0'的拷貝???
空間要求目標數組長度 ≥ strlen(src) + 1(否則溢出)緩沖區溢出的后果(程序崩潰、亂碼);如何提前檢查空間(sizeof(dest) >= ...????
手動實現原理循環逐字符拷貝,最后拷貝'\0';返回目標首地址循環終止條件(需包含'\0');手動添加'\0'的必要性???
常見錯誤目標空間不足、忘記拷貝'\0'、直接賦值數組名數組名不能直接賦值(dest = src錯誤);'\0'對字符串的重要性(%s輸出依賴)???
安全性提升可使用strncpy(dest, src, n)限制拷貝長度(n為目標數組最大容量 - 1)strncpy需手動添加'\0'(若源字符串超長);與strcpy的適用場景區別???

四、編程建議

  1. 優先使用標準庫函數: 理解strcpy原理后,實際開發中直接使用標準庫版本(經過優化和測試,更可靠),無需重復造輪子。

  2. 強制檢查空間: 拷貝前必須驗證目標數組長度 ≥ 源字符串長度 + 1,例如:

    #define DEST_LEN 20
    char dest[DEST_LEN];
    char src[] = "example";
    ?
    if (strlen(src) + 1 <= DEST_LEN) {strcpy(dest, src); ?// 安全
    } else {// 處理空間不足(如截斷或提示錯誤)
    }
  3. 了解替代函數strncpy(dest, src, n) 可指定最大拷貝長度(n),避免溢出(但需手動添加'\0'):

    strncpy(dest, src, DEST_LEN - 1); ?// 最多拷貝19個字符(留1個給'\0')
    dest[DEST_LEN - 1] = '\0'; ?// 確保結尾有'\0'

通過以上內容,可掌握strcpy的用法、原理及安全注意事項,明確其在字符串操作中的核心作用 —— 實現字符串的完整拷貝,同時規避緩沖區溢出等高危錯誤。

字符串函數(進階):strcat 與 strcmp 詳解

一、字符串連接函數strcat

1. 函數基礎與核心功能
  • 函數原型

    char *strcat(char *dest, const char *src);
  • 功能:將源字符串(src)連接到目標字符數組(dest)的末尾,形成新的字符串。

  • 核心邏輯

    1. dest中尋找第一個'\0'(原字符串的結尾);

    2. 從該位置開始,將src的字符(包括src'\0')逐個拷貝到dest

    3. 最終destsrc'\0'結尾,原dest'\0'被覆蓋。

  • 示例

    #include <stdio.h>
    #include <string.h>
    ?
    int main() {char dest[20] = "Hello"; ?// 目標數組(初始字符串:"Hello\0...")char src[] = " World"; ? ?// 源字符串(" World\0")strcat(dest, src); ? ? ? ?// 連接:在dest的'\0'位置開始拷貝srcprintf("連接后:%s\n", dest); ?// 輸出"Hello World"return 0;
    }
2. 使用規則與注意事項
(1)必須滿足的前提條件
  1. destsrc均為合法字符串(均以'\0'結尾):

    • dest'\0'strcat會越界尋找結尾(結果隨機);

    • src'\0',會越界拷貝(覆蓋dest后續內存)。

  2. dest空間必須足夠大: 所需空間 = strlen(dest) + strlen(src) + 1(原dest長度 + src長度 + 新'\0')。

    • 示例:dest初始長度 5("Hello"),src長度 6("World"),需至少 5+6+1=12 字節(dest定義為[20]足夠)。

  3. dest必須是可修改的字符數組: 不能是字符串常量(如strcat("Hello", "World")錯誤,字符串常量不可修改)。

3. 常見錯誤與規避
(1)空間不足導致溢出
char dest[10] = "Hello"; ?// 空間10字節(當前已用6字節:5字符+'\0')
char src[] = " World"; ? ?// 需6字節(5字符+'\0')
strcat(dest, src); ? ? ? ?// 總需6+6=12字節 > 10 → 溢出!
  • 后果:覆蓋dest相鄰內存,可能導致程序崩潰或輸出亂碼。

  • 規避:連接前檢查空間:

    if (strlen(dest) + strlen(src) + 1 <= sizeof(dest)) {strcat(dest, src); ?// 安全連接
    } else {printf("目標空間不足!\n");
    }
(2)dest不是合法字符串(無'\0'
char dest[10] = {'H', 'i'}; ?// 未顯式添加'\0',且未初始化的元素可能非0
char src[] = "!";
strcat(dest, src); ?// 尋找'\0'時越界,可能將src連接到隨機位置
  • 后果:連接位置錯誤(可能覆蓋dest的有效字符)。

  • 規避:確保

    dest

    初始化為合法字符串:

    char dest[10] = "Hi"; ?// 雙引號初始化,自動添加'\0'(安全)
4. 綜合應用:組合strcpystrcat

通過先拷貝、再連接,可構建復雜字符串:

// 示例:構建"Turbo C++"
char result[20];
// 步驟1:先拷貝"Turbo"到result
strcpy(result, "Turbo");
// 步驟2:連接空格
strcat(result, " ");
// 步驟3:連接"C++"
strcat(result, "C++");
printf("結果:%s\n", result); ?// 輸出"Turbo C++"
  • 優勢:每次操作自動維護'\0'位置,無需手動管理結尾。

二、字符串比較函數strcmp

1. 函數基礎與比較規則
  • 函數原型

    int strcmp(const char *str1, const char *str2);
  • 功能:按 ASCII 碼值逐字符比較兩個字符串,返回比較結果。

  • 比較規則

    1. 從第一個字符開始,逐個比較對應位置的字符(str1[i] vs str2[i]);

    2. 若遇到不同字符,返回兩者 ASCII 碼的差值(str1[i] - str2[i]);

    3. 若所有字符相同,比較長度:

      • 長度相同(均到'\0'):返回 0(相等);

      • 長度不同(一個先到'\0'):返回 “較長字符串 - 較短字符串” 的差值(通常簡化為 ±1)。

  • 返回值約定

    • >0str1 > str2str1在字典序中更靠后);

    • =0str1 == str2(完全相同);

    • <0str1 < str2str1在字典序中更靠前)。

2. 比較示例與解析
示例比較過程返回值結論
strcmp("ABC", "ABC")所有字符相同,均到'\0'0相等
strcmp("BBC", "ABC")第一個字符:'B'(66) > 'A'(65),停止比較1str1 > str2
strcmp("ABD", "ABC")前兩位相同,第三位 'D'(68) > 'C'(67),停止比較1str1 > str2
strcmp("AB", "ABC")前兩位相同,str1先到'\0'str2還有 'C')-1str1 < str2
strcmp("a", "A")'a'(97) > 'A'(65)32str1 > str2(ASCII 差值)
3. 使用注意事項
(1)不能用==直接比較字符串
// 錯誤示例:比較的是地址,而非內容
if ("hello" == "world") { ... } ?// 比較兩個字符串常量的地址(永遠為假)
if (str1 == str2) { ... } ? ? ? ?// 比較數組首地址(非內容)
  • 正確做法:用

    strcmp

    比較內容:

    if (strcmp(str1, str2) == 0) { ?// 內容相等printf("兩字符串相同\n");
    }
(2)返回值不一定是 ±1(依賴實現)

標準僅規定返回 “正 / 負 / 零”,未規定具體數值(如strcmp("a", "A")可能返回 32,而非 1)。

  • 編程建議

    :判斷時用

    >0

    /

    <0

    /

    ==0

    ,而非固定值:

    if (strcmp(s1, s2) > 0) { ... } ?// 正確:s1 > s2
    // 錯誤:依賴具體返回值(如1)
    if (strcmp(s1, s2) == 1) { ... }
(3)必須傳入合法字符串(以'\0'結尾)

str1str2'\0'strcmp會越界比較(結果隨機):

char s1[] = {'a', 'b'}; ?// 無'\0'
char s2[] = "abc";
strcmp(s1, s2); ?// 越界比較(結果不可預測)

三、知識小結

知識點核心內容考試重點 / 易混淆點難度系數
strcat 函數連接srcdest末尾(覆蓋dest'\0',添加src'\0');需dest空間足夠空間計算(strlen(dest)+strlen(src)+1);destsrc必須有'\0'???
strcat 常見錯誤空間不足導致溢出;dest'\0'導致連接位置錯誤如何提前檢查空間(sizeof(dest) >= ...);初始化dest為合法字符串????
strcmp 比較規則逐字符比較 ASCII 碼;遇不同字符或'\0'停止;返回正 / 負 / 零表示大小關系==的區別(地址比較 vs 內容比較);返回值的判斷(>0而非==1???
strcmp 特殊案例前序字符相同但長度不同時,較短字符串更小(如 "AB" < "ABC")區分 “長度” 與 “字典序”(短字符串不一定小,需前序字符相同)???
綜合應用strcpy拷貝初始內容 + strcat連接后續內容,構建復雜字符串每次操作的空間檢查;'\0'的自動維護機制???

四、編程建議

  1. strcat 使用流程

    // 1. 定義足夠大的目標數組
    char dest[100];
    // 2. 初始化目標數組(確保有'\0')
    strcpy(dest, "初始內容");
    // 3. 連接前檢查空間
    if (strlen(dest) + strlen(src) + 1 <= sizeof(dest)) {strcat(dest, src); ?// 4. 安全連接
    }
  2. strcmp 正確判斷方式

    int res = strcmp(s1, s2);
    if (res == 0) {printf("相等\n");
    } else if (res > 0) {printf("s1 > s2\n");
    } else {printf("s1 < s2\n");
    }
  3. 替代函數(更安全)

    • strncat(dest, src, n):限制連接的最大字符數(n),避免溢出;

    • strncmp(s1, s2, n):僅比較前n個字符,適合長字符串部分比較。

通過以上內容,可掌握strcat(連接)和strcmp(比較)的核心用法,理解字符串操作中 “空間管理” 和 “'\0'維護” 的重要性,規避緩沖區溢出、比較錯誤等常見問題。

字符串函數(擴展):帶長度限制與查找類函數詳解

一、帶長度限制的拷貝與連接函數

1. 字符串部分拷貝函數strncpy
(1)函數功能與核心區別
  • 函數原型:

    char *strncpy(char *dest, const char *src, size_t n);
  • 核心功能:從源字符串src拷貝最多n個字符到目標數組dest(區別于strcpy的 “完整拷貝”)。

  • strcpy的關鍵差異:

    特性strcpy(dest, src)strncpy(dest, src, n)
    拷貝范圍完整拷貝(直到src'\0'最多拷貝n個字符(無論src是否結束)
    '\0'處理自動拷貝src'\0'僅當src長度≤n時,才用'\0'填充剩余空間(否則不補'\0'
    目標串剩余部分被覆蓋(直到'\0'未被覆蓋的部分保留原值(僅替換前n個字符)
(2)示例與特殊行為解析
#include <stdio.h>
#include <string.h>
?
int main() {char dest[10] = "dot.com"; ?// 初始:d o t . c o m \0 ...char src[] = "make"; ? ? ? ?// src長度4(不含'\0')strncpy(dest, src, 4); ? ? ?// 拷貝src的前4個字符到destprintf("dest結果:%s\n", dest); ?// 輸出"make.com"(前4個字符被替換,剩余保留)return 0;
}
  • 行為分析:

    • 僅替換dest的前 4 個字符('d','o','t','.''m','a','k','e');

    • src長度(4)等于n(4),且src'\0'"make"'\0'未被拷貝),但dest原有'\0'在第 7 位('m','a','k','e','.','c','o','m','\0'),因此可正常輸出。

(3)使用注意事項
  1. '\0'可能缺失:若src長度≥n,拷貝后destn個字符無'\0'(需手動添加,否則不是合法字符串)。

    char dest[5], src[] = "hello";
    strncpy(dest, src, 4); ?// dest為'h','e','l','l'(無'\0')
    dest[4] = '\0'; ? ? ? ? // 手動添加結束符(必須!)
  2. 空間仍需足夠:目標數組dest長度至少為n(否則拷貝時越界)。

  3. 短源字符串的填充:若src長度<n,剩余位置會自動用'\0'填充(如src長度 2,n=5,則拷貝 2 個字符后補 3 個'\0')。

2. 字符串部分連接函數strncat
(1)函數功能與使用
  • 函數原型

    char *strncat(char *dest, const char *src, size_t n);
  • 功能:在dest的末尾追加srcn個字符(或src的全部字符,以較短者為準),自動添加'\0'

  • strcat的區別strcat追加完整srcstrncat可限制追加長度(避免溢出)。

  • 示例

    char dest[20] = "Hello";
    char src[] = "World!";
    strncat(dest, src, 3); ?// 追加src的前3個字符"Wor"
    printf("結果:%s\n", dest); ?// 輸出"HelloWor"(自動添加'\0')
(2)關鍵特性
  • 自動添加'\0':無論追加多少字符,最終dest都會以'\0'結尾(安全)。

  • 目標空間要求dest總長度需≥strlen(dest) + min(n, strlen(src)) + 1(原長度 + 追加長度 + '\0')。

3. 字符串部分比較函數strncmp
(1)函數功能與應用
  • 函數原型

    int strncmp(const char *str1, const char *str2, size_t n);
  • 功能:比較str1str2n個字符(區別于strcmp的 “比較到'\0'”)。

  • 返回值:與strcmp一致(正 / 負 / 零表示大于 / 小于 / 等于),但僅基于前n個字符。

  • 典型應用:忽略字符串末尾的無關字符(如換行符)。

    // 比較"quit"和"quit\n"的前4個字符(結果相等)
    if (strncmp(input, "quit", 4) == 0) {printf("檢測到退出指令\n");
    }
(2)注意事項
  • n大于兩字符串的長度,比較到較短字符串的'\0'時停止(與strcmp邏輯一致)。

  • 適用于 “前綴匹配” 場景(如判斷字符串是否以特定前綴開頭)。

二、忽略大小寫比較函數strcasecmp

  • 函數原型

    int strcasecmp(const char *str1, const char *str2);
  • 功能:比較兩個字符串,忽略字母大小寫(如'A''a'視為相等)。

  • 應用場景:用戶輸入容錯(如 “QUIT”“Quit”“quit” 均視為相同指令)。

  • 示例

    if (strcasecmp(input, "quit") == 0) {printf("退出程序\n"); ?// 匹配"quit"、"QUIT"、"Quit"等
    }
  • 注意:非字母字符(如數字、符號)仍按 ASCII 碼嚴格比較(如'!''!'相等,'1''2'不等)。

三、字符與子串查找函數

1. 字符查找函數strchrstrrchr
(1)strchr:查找字符首次出現位置
  • 函數原型:

    char *strchr(const char *s, int c); ?// c為字符的ASCII碼(如查找'a'可傳97或'a')
  • 功能:在字符串s中查找字符c首次出現的位置,返回該位置的地址;未找到返回NULL

  • 示例:

    char s[] = "hello world";
    char *p = strchr(s, 'o'); ?// 查找首個'o'
    if (p != NULL) {printf("找到字符,位置:%ld\n", p - s); ?// 輸出4(下標從0開始)printf("從該位置開始的字符串:%s\n", p); ?// 輸出"o world"
    }
(2)strrchr:查找字符最后一次出現位置
  • 函數原型:

    char *strrchr(const char *s, int c);
  • 功能:查找字符c在s中最后一次出現的位置區別于

    strchr

    的 “首次”。

    char s[] = "hello world";
    char *p = strrchr(s, 'o'); ?// 查找最后一個'o'
    printf("位置:%ld\n", p - s); ?// 輸出7("world"中的'o')
(3)關鍵技巧
  • 計算下標:找到的地址與字符串首地址的差值即為字符下標(p - s)。

  • 查找'\0'strchr(s, '\0')會返回s末尾'\0'的地址(可用于計算字符串長度:strchr(s, '\0') - s等價于strlen(s))。

2. 子串查找函數strstr
(1)函數功能與應用
  • 函數原型

    char *strstr(const char *haystack, const char *needle);
  • 功能:在長字符串haystack中查找子串needle首次出現的位置(如在 “hello world” 中查找 “lo”)。

  • 返回值:找到則返回子串首字符地址;未找到返回NULL

  • 示例

    char str[] = "ho are you";
    char sub[] = "are";
    char *p = strstr(str, sub); ?// 查找"are"在str中的位置
    if (p != NULL) {printf("子串位置:%ld\n", p - str); ?// 輸出4(從0開始計數)printf("子串及后續:%s\n", p); ? ? ? // 輸出"are you"
    }
(2)使用注意事項
  • 子串為空:若needle是空字符串(""),返回haystack的首地址(標準規定)。

  • 區分大小寫:如需忽略大小寫,使用strcasestr(非標準但多數編譯器支持)。

  • 空指針檢查:未找到時返回NULL,使用前必須判斷(否則訪問NULL會崩潰)。

三、知識小結

知識點核心內容考試重點 / 易混淆點難度系數
strncpy拷貝src的前n個字符到dest;若src長≥n,需手動加'\0'strcpy的區別(是否限制長度);'\0'的手動添加(否則目標串不合法)???
strncat追加src的前n個字符到dest末尾,自動加'\0';需目標空間足夠目標空間計算(原長度 + 追加長度 + 1);與strcat的長度限制差異??
strncmp比較前n個字符,用于前綴匹配或忽略末尾字符(如"quit""quit\n"比較范圍僅限前n個字符;返回值規則與strcmp一致???
strcasecmp忽略大小寫比較字符串(字母不區分大小寫,符號嚴格比較)應用場景(用戶輸入容錯);非字母字符的嚴格比較??
strchr/strrchr查找字符首次 / 最后一次出現位置(返回地址);通過地址差值計算下標地址差值轉下標(p - s);查找'\0'的特殊用法(等價于strlen???
strstr在長串中查找子串首次出現位置(返回地址);未找到返回NULL子串位置計算(p - haystack);NULL返回值的檢查(避免崩潰)????

四、編程實踐建議

  1. 優先使用帶長度限制的函數strncpystrncatstrncmp比無長度限制的函數更安全(減少溢出風險)。

  2. 手動添加'\0':使用strncpy時,若拷貝長度等于nsrc'\0',務必手動添加(dest[n] = '\0')。

  3. 檢查返回值:查找類函數(strchrstrstr)返回NULL時,需避免訪問(如if (p != NULL) { ... })。

  4. 結合指針運算:通過 “找到的地址 - 首地址” 快速計算下標(無需循環遍歷)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915072.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915072.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915072.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

.NET Core EFCore零基礎快速入門簡單使用

一、什么是 Entity Framework (EF) Core Entity Framework (EF) Core 是輕量化、可擴展和跨平臺版的對象關系映射程序 (O/RM)數據訪問技術&#xff0c;。 它將開發人員從編寫大量 SQL 語句中解放出來。 二、EF的相關程序包 Microsoft.EntityFrameworkCore 核心程序包&#x…

AAC音頻格式

目錄 AAC音頻格式介紹 主要特點 技術優勢 常見文件擴展名 應用領域 AAC與PCM的區別與優勢對比 基本概念差異 主要技術區別 各自優勢 PCM的優勢 AAC的優勢 應用場景選擇 AAC音頻數據格式解析 1. AAC 文件格式 (1) ADIF (Audio Data Interchange Format) (2) ADT…

pom.xml文件中的${}變量從哪里傳值

在 Maven 的 pom.xml 文件中&#xff0c;${} 格式的變量&#xff08;稱為屬性占位符&#xff09;的值來源主要有以下幾種途徑&#xff1a; 1. ?內置屬性&#xff08;Maven 預定義&#xff09;?? ${project.basedir}&#xff1a;項目根目錄${project.version}&#xff1a;項…

【人工智能】項目案例分析:使用TensorFlow進行大規模對象檢測

????歡迎大家來到我們的天空???? ?? 作者簡介:我們的天空 ??《頭銜》:大廠高級軟件測試工程師,阿里云開發者社區專家博主,CSDN人工智能領域新星創作者。 ??《博客》:人工智能,深度學習,機器學習,python,自然語言處理,AIGC等分享。 所屬的專欄:TensorF…

C++---cout、cerr、clog

在C編程里&#xff0c;cout、cerr和clog是標準庫提供的重要輸出流對象&#xff0c;在數據輸出方面發揮著關鍵作用。 一、cout&#xff1a;標準輸出流 cout 是 std::ostream 類的對象&#xff0c;其作用是向標準輸出設備&#xff08;一般是控制臺&#xff09;輸出數據。它和 C 語…

脈沖神經網絡(Spiking Neural Network, SNN)與知識蒸餾(Knowledge Distillation, KD)

目錄 脈沖神經網絡&#xff08;Spiking Neural Network, SNN&#xff09; 知識蒸餾&#xff08;Knowledge Distillation, KD&#xff09; 三種類別 三種變體 脈沖神經網絡&#xff08;Spiking Neural Network, SNN&#xff09; 收到生物神經系統的啟發&#xff0c;設計的&a…

使用Java完成下面項目

第一題&#xff1a;從控制臺輸入十個學生的成績&#xff0c;使用list集合來保存數據&#xff0c; 遍歷并打印其中成績不及格的成績&#xff0c;打印最高成績&#xff0c;最低成績&#xff0c;并計算及格率代碼如下public class Home1 {public static void main(String[] args) …

龍虎榜——20250718

上證指數今天上漲收陽線&#xff0c;繼續在5天均線保持強勢上漲&#xff0c;個股下跌稍多&#xff0c;大盤股上漲為主。深證指數收小陽線&#xff0c;繼續在5天均線上&#xff0c;總體保持強勢&#xff0c;調整更多是小票。2025年7月18日龍虎榜行業方向分析1. 醫藥醫療? 代表標…

2025年華為認證之HCIE-云計算方向的報考流程

一、先搞明白&#xff1a;HCIE - 云計算認證到底是啥&#xff1f; HCIE - 云計算&#xff08;華為認證 ICT 專家 - 云計算&#xff09;是華為體系里云計算領域的頂級認證&#xff0c;說白了&#xff0c;就是證明你有能力搞定大型企業的云平臺設計、部署和運維。現在政企、金融…

什么是私有化部署企業即時通訊?吱吱企業即時通訊安全嗎?

在企業數字化轉型加速的今天&#xff0c;溝通工具的選擇已經從滿足簡單溝通&#xff0c;升級為“安全、高效、可控”。其中&#xff0c;“私有化部署企業即時通訊”成為許多中小型企業、跨國企業以及數據敏感型企業的核心需求。 那么&#xff0c;究竟什么是私有化部署&#xff…

Vue3 中使用 Element Plus 實現自定義按鈕的 ElNotification 提示框

在 Vue3 項目中&#xff0c;我們經常會用到 ElNotification 作為消息提醒組件&#xff0c;尤其是在異步操作、任務完成或用戶需要交互確認時。然而&#xff0c;Element Plus 默認的 Notification 是非交互式的&#xff0c;不能直接嵌入按鈕或事件。 今天我們來實現一個帶自定義…

下載webrtc M114版本源碼只能使用外網googlesource源-命令版

聲網、國內源都不行&#xff0c;只能外網googlesource源&#xff01;&#xff01;&#xff01; 二、創建 Ubuntu 容器&#xff08;帶目錄掛載&#xff09; 拉取Ubuntu鏡像 docker pull ubuntu:22.04創建并啟動容器&#xff08;掛載Windows目錄到容器&#xff09; docker run -i…

Linux運維新手的修煉手扎之第21天

Nginx服務和Tomcat服務1 負載均衡語法格式&#xff1a;upstream[一個或多個]rootubuntu24-13:~# vim /etc/nginx/conf.d/vhost.confupstream group1 {server 10.0.0.16;}upstream group2 {server 10.0.0.14;}server {listen 80;server_name sswang1.magedu.com;location / {pro…

TrOCR: 基于Transformer的光學字符識別方法,使用預訓練模型

溫馨提示&#xff1a; 本篇文章已同步至"AI專題精講" TrOCR: 基于Transformer的光學字符識別方法&#xff0c;使用預訓練模型 摘要 文本識別是文檔數字化中的一個長期研究問題。現有方法通常基于CNN進行圖像理解&#xff0c;基于RNN進行字符級文本生成。此外&#…

西門子工業軟件全球高級副總裁兼大中華區董事總經理梁乃明先生一行到訪庭田科技

概要2025年6月&#xff0c;西門子工業軟件全球高級副總裁兼大中華區董事總經理梁乃明先生一行到訪我司。庭田科技總經理聶春文攜銷售團隊對西門子代表團表示熱烈歡迎&#xff0c;并就當前業務發展方向及未來行業聚焦領域與代表團展開深入交流。 聶春文總經理及銷售團隊陪同西門…

在 Jenkins 中使用 SSH 部署密鑰

本文檔介紹了如何在 Jenkins 中配置 SSH 部署密鑰&#xff0c;以便更穩定地拉取 Git 倉庫代碼&#xff0c;避免常見的 RPC 錯誤。 1. 背景 在使用 Jenkins 進行持續集成時&#xff0c;常常需要從 Git 倉庫拉取代碼。如果使用 HTTP/HTTPS 協議&#xff0c;有時會遇到 RPC 錯誤&…

小紅書采集工具:無水印圖片一鍵獲取,同步采集筆記與評論

我用python語言開發了一款名為“爬xhs圖片軟件”的工具&#xff0c;該工具不僅能采集圖片&#xff0c;還可獲取筆記數據、評論數據等內容。 軟件界面長這個樣子&#xff1a; 采集到的圖片&#xff1a;演示視頻&#xff1a;https://live.csdn.net/v/485813介紹文章、想你所想&am…

Java行為型模式---命令模式

命令模式基礎概念命令模式&#xff08;Command Pattern&#xff09;是一種行為型設計模式&#xff0c;其核心思想是將請求封裝為一個對象&#xff0c;從而使你可以用不同的請求對客戶進行參數化&#xff0c;對請求排隊或記錄請求日志&#xff0c;以及支持可撤銷的操作。命令模式…

Android性能優化之包體積優化

一、包體積組成與瓶頸分析 1. 典型 APK 結構占比 #mermaid-svg-KEUQMlEifvHlk1CV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KEUQMlEifvHlk1CV .error-icon{fill:#552222;}#mermaid-svg-KEUQMlEifvHlk1CV .erro…

開源Web播放器推薦與選型指南

Video.js3&#xff1a;是市面上最流行的免費、開源 HTML5 視頻播放器之一。可用于直播和點播&#xff0c;支持 HLS、DASH、WebM 和 MP4 等多種格式。它可高度自定義&#xff0c;開源社區中有很多皮膚可供選用&#xff0c;還可通過插件配置 Multi - DRM、廣告插入、字幕等功能&a…