最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言字符串安全查找的三種方式詳解

 更新時(shí)間:2025年10月09日 08:50:12   作者:byte輕騎兵  
C語言開發(fā)中,字符串操作是安全漏洞的重災(zāi)區(qū),傳統(tǒng)函數(shù)缺乏邊界檢查,若輸入字符串未正確以\0結(jié)尾,極易觸發(fā)緩沖區(qū)溢出,導(dǎo)致程序崩潰或被惡意利用,所以本文給大家介紹了C語言字符串安全查找的三種方式,并作了詳細(xì)的分析,需要的朋友可以參考下

引言

在 C 語言開發(fā)中,字符串操作是安全漏洞的 “重災(zāi)區(qū)”—— 傳統(tǒng)函數(shù)(如strchr、strrchr、strstr)缺乏邊界檢查,若輸入字符串未正確以\0結(jié)尾,極易觸發(fā)緩沖區(qū)溢出,導(dǎo)致程序崩潰或被惡意利用(如注入攻擊)。

為解決這一問題,C11 標(biāo)準(zhǔn)(ISO/IEC 9899:2011) 引入 “邊界檢查接口”(Bounds-checking interfaces),其中strchr_s、strrchr_s、strstr_s便是傳統(tǒng)查找函數(shù)的安全增強(qiáng)版本。它們通過增加長度參數(shù)、明確錯(cuò)誤處理,從根源上降低安全風(fēng)險(xiǎn),成為安全關(guān)鍵型應(yīng)用(如嵌入式系統(tǒng)、金融軟件)的首選工具。

一、安全字符串函數(shù)概述

strchr_s、strrchr_s、strstr_s保留了傳統(tǒng)函數(shù)的核心查找功能,同時(shí)新增以下安全特性

  1. 強(qiáng)制傳入字符串長度參數(shù),限制操作范圍,防止越界訪問;
  2. 通過返回值(錯(cuò)誤碼)報(bào)告異常,而非依賴 “未定義行為”;
  3. 主動(dòng)校驗(yàn)無效參數(shù)(如空指針、超范圍長度);
  4. 檢查字符串是否在指定長度內(nèi)正確終止(避免處理不完整字符串)。

注:使用這些函數(shù)需先定義宏__STDC_WANT_LIB_EXT1__(通常在包含<string.h>前),以啟用 C11 標(biāo)準(zhǔn)的安全接口。

二、strchr_s:安全的正向字符查找

1. 函數(shù)簡介

strchr_s用于在字符串中從左到右查找第一個(gè)匹配字符,核心優(yōu)勢(shì)是通過 “長度參數(shù) + 錯(cuò)誤校驗(yàn)”,確保查找不超出緩沖區(qū)邊界。

2. 函數(shù)原型

errno_t strchr_s(char const* str, rsize_t strsz, int c, char const** result);
參數(shù)名說明
str待查找的源字符串指針(需以\0結(jié)尾,且非空)
strsz源字符串的最大長度(含\0,通常用sizeof(str)獲取數(shù)組長度)
c目標(biāo)字符(雖為int類型,實(shí)際會(huì)被轉(zhuǎn)換為char,兼容EOF)
result輸出參數(shù):存儲(chǔ)查找結(jié)果(成功則指向匹配字符,失敗則為NULL)

返回值

  • 成功(找到 / 未找到字符):返回0;
  • 失敗(參數(shù)無效 / 長度異常):返回非零錯(cuò)誤碼(如EINVAL、ESPACE)。

錯(cuò)誤碼含義:

  • strresultNULL(無效指針);
  • ESPACEstrsz0、超過RSIZE_MAX(通常為SIZE_MAX/2),或字符串未在strsz內(nèi)終止。

3. 實(shí)現(xiàn)邏輯(偽代碼)

function strchr_s(str: const char*, strsz: rsize_t, c: int, result: const char**) -> errno_t:
    // 1. 校驗(yàn)無效指針
    if str == NULL or result == NULL:
        return EINVAL
    
    // 2. 校驗(yàn)長度合法性
    if strsz == 0 or strsz > RSIZE_MAX:
        *result = NULL
        return ESPACE
    
    // 3. 轉(zhuǎn)換目標(biāo)字符(int→char)
    c_char = (char)c
    
    // 4. 正向遍歷查找
    for i from 0 to strsz - 1:
        if str[i] == c_char:
            *result = &str[i]  // 找到匹配,記錄位置
            return 0
        if str[i] == '\0':
            break  // 已達(dá)字符串實(shí)際結(jié)尾,停止遍歷
    
    // 5. 未找到字符(非錯(cuò)誤,返回0)
    *result = NULL
    return 0

4. 工作流程示意圖

5. 使用場景

strchr_s適用于所有需查找單個(gè)字符的場景,尤其適合:

  1. 處理不可信輸入(如用戶輸入的郵箱、配置項(xiàng));
  2. 驗(yàn)證字符串格式(如檢查郵箱是否含@、路徑是否含分隔符);
  3. 分割字符串(如按:分割鍵值對(duì)"name:zhangsan")。

6. 示例代碼

#define __STDC_WANT_LIB_EXT1__ 1  // 啟用C11安全函數(shù)
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main() {
    // 場景1:驗(yàn)證郵箱格式(查找@)
    char email[] = "user@example.com";
    const char* result;
    errno_t err;  // 存儲(chǔ)錯(cuò)誤碼

    // 調(diào)用strchr_s查找@
    err = strchr_s(email, sizeof(email), '@', &result);

    // 錯(cuò)誤處理
    if (err != 0) {
        printf("查找失敗!錯(cuò)誤碼:%d\n", err);
        return 1;
    }

    // 結(jié)果處理
    if (result != NULL) {
        printf("找到'@',位置(索引):%td\n", result - email);
        printf("郵箱用戶名:%.*s\n", (int)(result - email), email);  // 截取用戶名
        printf("郵箱域名:%s\n", result + 1);                      // 截取域名
    } else {
        printf("未找到'@',郵箱格式非法!\n");
    }

    // 場景2:查找超出字符串長度的字符(邊界測試)
    char buffer[10] = "test";  // 緩沖區(qū)大小10,實(shí)際字符串長度4(含\0)
    err = strchr_s(buffer, 10, 'x', &result);
    if (err == 0 && result == NULL) {
        printf("\n在buffer中未找到'x'(邊界檢查生效)\n");
    }

    return 0;
}

運(yùn)行結(jié)果

找到'@',位置(索引):4

郵箱用戶名:user

郵箱域名:example.com

在buffer中未找到'x'(邊界檢查生效)

7 注意事項(xiàng)

  • 長度參數(shù)必須含\0strsz需包含字符串的終止符\0,如char str[] = "abc"strsz應(yīng)為4(而非3);
  • 錯(cuò)誤碼優(yōu)先校驗(yàn):不能僅通過result是否為NULL判斷成功 —— 需先檢查err是否為0(如err=EINVAL時(shí)result也為NULL);
  • c的類型轉(zhuǎn)換cint是為兼容EOF(值為-1),函數(shù)內(nèi)部會(huì)轉(zhuǎn)為char,無需手動(dòng)處理;
  • 查找\0的特殊情況:若c='\0',函數(shù)會(huì)返回指向字符串末尾\0的指針(符合 C11 標(biāo)準(zhǔn))。

三、strrchr_s:安全的反向字符查找

1. 函數(shù)簡介

strrchr_sstrchr_s反向版本,用于從字符串末尾(右→左)查找最后一個(gè)匹配字符。同樣通過邊界檢查,避免越界訪問,核心場景是 “提取最右側(cè)字符相關(guān)內(nèi)容”(如文件名、后綴)。

2. 函數(shù)原型

errno_t strrchr_s(char const* str, rsize_t strsz, int c, char const** result);

參數(shù)、返回值、錯(cuò)誤碼與strchr_s完全一致,僅查找方向不同。

3. 實(shí)現(xiàn)邏輯(偽代碼)

function strrchr_s(str: const char*, strsz: rsize_t, c: int, result: const char**) -> errno_t:
    // 1. 校驗(yàn)無效指針
    if str == NULL or result == NULL:
        return EINVAL
    
    // 2. 校驗(yàn)長度合法性
    if strsz == 0 or strsz > RSIZE_MAX:
        *result = NULL
        return ESPACE
    
    // 3. 轉(zhuǎn)換目標(biāo)字符
    c_char = (char)c
    
    // 4. 第一步:定位字符串實(shí)際結(jié)尾(找到\0)
    str_end = NULL
    for i from 0 to strsz - 1:
        if str[i] == '\0':
            str_end = &str[i]
            break
    if str_end == NULL:  // 字符串未在strsz內(nèi)終止
        *result = NULL
        return ESPACE
    
    // 5. 第二步:從結(jié)尾反向查找
    current = str_end - 1  // 從\0的前一個(gè)字符開始
    while current >= str:
        if *current == c_char:
            *result = current
            return 0
        current = current - 1
    
    // 6. 特殊情況:查找\0
    if c_char == '\0':
        *result = str_end
        return 0
    
    // 7. 未找到字符
    *result = NULL
    return 0

4. 工作流程示意圖

5. 使用場景

strrchr_s的核心場景是 “提取最右側(cè)字符后的內(nèi)容”,典型案例:

  • 從文件路徑中提取文件名(如"/home/user/test.c""test.c",查找最后一個(gè)/);
  • 獲取文件后綴(如"image.png"".png",查找最后一個(gè).);
  • 分割帶重復(fù)分隔符的字符串(如"a,b,c,d""d",查找最后一個(gè),)。

6. 示例代碼(提取文件名與后綴)

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <errno.h>

// 安全提取文件名(支持/和\路徑分隔符)
const char* get_filename_s(const char* path, rsize_t path_len) {
    const char* result;
    errno_t err;

    // 第一步:查找最后一個(gè)/
    err = strrchr_s(path, path_len, '/', &result);
    if (err != 0) return NULL;  // 參數(shù)錯(cuò)誤,返回空

    if (result != NULL) {
        return result + 1;  // 跳過/,返回文件名起始位置
    }

    // 第二步:若未找到/,查找最后一個(gè)\(Windows路徑)
    err = strrchr_s(path, path_len, '\\', &result);
    if (err != 0) return NULL;

    return (result != NULL) ? (result + 1) : path;  // 無分隔符則返回原路徑
}

int main() {
    // 測試不同路徑格式
    char path1[] = "/home/user/documents/report.pdf";  // Linux路徑
    char path2[] = "C:\\Users\\user\\photos\\vacation.jpg";  // Windows路徑
    char path3[] = "readme.txt";  // 無路徑(僅文件名)

    // 提取文件名
    const char* filename1 = get_filename_s(path1, sizeof(path1));
    const char* filename2 = get_filename_s(path2, sizeof(path2));
    const char* filename3 = get_filename_s(path3, sizeof(path3));

    printf("路徑1的文件名:%s\n", filename1);
    printf("路徑2的文件名:%s\n", filename2);
    printf("路徑3的文件名:%s\n", filename3);

    // 提取文件后綴(查找最后一個(gè).)
    const char* ext;
    errno_t err = strrchr_s(filename1, strlen(filename1) + 1, '.', &ext);
    if (err == 0 && ext != NULL) {
        printf("\n文件1的后綴:%s\n", ext);
    }

    return 0;
}

運(yùn)行結(jié)果

路徑1的文件名:report.pdf
路徑2的文件名:vacation.jpg
路徑3的文件名:readme.txt

文件1的后綴:.pdf

7 注意事項(xiàng)

  • 路徑以分隔符結(jié)尾的處理:若路徑為"/home/user/docs/"(末尾為/),result會(huì)指向該/,此時(shí)result+1\0(空字符串),需額外判斷;
  • 性能對(duì)比strrchr_s需先遍歷到字符串結(jié)尾,再反向查找,效率略低于strchr_s,但安全性無差異;
  • strchr_s的共性問題:同樣需注意長度參數(shù)含\0、錯(cuò)誤碼優(yōu)先校驗(yàn)、c的類型轉(zhuǎn)換。

四、strstr_s:安全的子串查找

1. 函數(shù)簡介

strstr_s用于在主串(haystack)中查找子串(needle)的首次出現(xiàn)位置,是strstr的安全版本。它通過同時(shí)校驗(yàn)主串和子串的長度,防止 “子串越界” 或 “主串未終止” 導(dǎo)致的安全問題,核心場景是 “多字符匹配”(如關(guān)鍵詞搜索、協(xié)議解析)。

2. 函數(shù)原型

errno_t strstr_s(char const* haystack, rsize_t haystacksz, 
                 char const* needle, rsize_t needlesz, 
                 char const** result);
參數(shù)名說明
haystack主串(待查找的字符串,需以\0結(jié)尾)
haystacksz主串的最大長度(含\0
needle子串(目標(biāo)查找內(nèi)容,需以\0結(jié)尾)
needlesz子串的最大長度(含\0
result輸出參數(shù):成功則指向主串中子串的起始位置,失敗則為NULL

返回值與錯(cuò)誤碼

  • 成功(找到 / 未找到子串):返回0;
  • 失?。悍祷胤橇沐e(cuò)誤碼(EINVAL/ESPACE/EILSEQ)。

新增錯(cuò)誤碼EILSEQ:子串長度(實(shí)際長度)大于主串長度,不可能匹配。

3. 實(shí)現(xiàn)邏輯(偽代碼:樸素算法)

strstr_s的核心是 “主串遍歷 + 子串逐字符比對(duì)”,以下為易理解的樸素實(shí)現(xiàn)(標(biāo)準(zhǔn)庫通常用 KMP/BM 算法優(yōu)化,時(shí)間復(fù)雜度從O(n*m)降至O(n+m)):

function strstr_s(haystack: const char*, haystacksz: rsize_t,
                 needle: const char*, needlesz: rsize_t,
                 result: const char**) -> errno_t:
    // 1. 校驗(yàn)無效指針
    if haystack == NULL or needle == NULL or result == NULL:
        return EINVAL
    
    // 2. 校驗(yàn)長度合法性
    if haystacksz == 0 or haystacksz > RSIZE_MAX or
       needlesz == 0 or needlesz > RSIZE_MAX:
        *result = NULL
        return ESPACE
    
    // 3. 計(jì)算主串/子串的實(shí)際長度(不含\0)
    haystack_len = 0
    while haystack_len < haystacksz and haystack[haystack_len] != '\0':
        haystack_len += 1
    if haystack_len == haystacksz and haystack[haystack_len-1] != '\0':
        *result = NULL
        return ESPACE  // 主串未終止
    
    needle_len = 0
    while needle_len < needlesz and needle[needle_len] != '\0':
        needle_len += 1
    if needle_len == needlesz and needle[needle_len-1] != '\0':
        *result = NULL
        return ESPACE  // 子串未終止
    
    // 4. 特殊情況:子串為空(返回主串起始位置)
    if needle_len == 0:
        *result = haystack
        return 0
    
    // 5. 子串長于主串(直接返回未找到)
    if needle_len > haystack_len:
        *result = NULL
        return 0
    
    // 6. 樸素查找:主串遍歷+子串比對(duì)
    max_pos = haystack_len - needle_len  // 主串遍歷的最大位置
    for i from 0 to max_pos:
        match = true
        // 逐字符比對(duì)子串
        for j from 0 to needle_len - 1:
            if haystack[i+j] != needle[j]:
                match = false
                break
        if match:
            *result = &haystack[i]
            return 0
    
    // 7. 未找到子串
    *result = NULL
    return 0

4. 工作流程示意圖

5. 使用場景

strstr_s是多字符匹配的核心工具,典型場景:

  • 文本關(guān)鍵詞搜索(如日志中查找 “error”“warning”);
  • 協(xié)議解析(如從"HTTP/1.1 200 OK"中提取 “200” 狀態(tài)碼);
  • URL 處理(如從"https://github.com"中提取"github.com");
  • 敏感詞過濾(如用戶輸入中檢測違規(guī)詞匯)。

6. 示例代碼(敏感詞檢測與 URL 解析)

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <errno.h>

// 安全檢測文本是否含敏感詞
int check_sensitive_word(const char* text, rsize_t text_len,
                        const char* word, rsize_t word_len) {
    const char* result;
    errno_t err = strstr_s(text, text_len, word, word_len, &result);

    if (err != 0) {
        printf("檢測失??!錯(cuò)誤碼:%d\n", err);
        return -1;  // 錯(cuò)誤標(biāo)識(shí)
    }
    return (result != NULL) ? 1 : 0;  // 1=含敏感詞,0=不含
}

// 安全提取URL域名(支持http/https)
const char* get_url_domain(const char* url, rsize_t url_len) {
    const char* result;
    errno_t err;

    // 先查找"https://"(長度8)
    err = strstr_s(url, url_len, "https://", 9, &result);  // 9=8+1(含\0)
    if (err == 0 && result != NULL) {
        return result + 8;
    }

    // 再查找"http://"(長度7)
    err = strstr_s(url, url_len, "http://", 8, &result);   // 8=7+1
    if (err == 0 && result != NULL) {
        return result + 7;
    }

    return url;  // 非HTTP/HTTPS協(xié)議,返回原URL
}

int main() {
    // 場景1:敏感詞檢測
    char log[] = "2024-06-01: user input contains 'badword'";
    char sensitive[] = "badword";
    int has_sensitive = check_sensitive_word(log, sizeof(log), 
                                            sensitive, sizeof(sensitive));
    
    if (has_sensitive == 1) {
        printf("日志含敏感詞:%s\n", sensitive);
    } else if (has_sensitive == 0) {
        printf("日志無敏感詞\n");
    }

    // 場景2:URL域名提取
    char url1[] = "https://github.com";
    char url2[] = "http://www.baidu.com";
    char url3[] = "ftp://ftp.example.com";  // 非HTTP協(xié)議

    const char* domain1 = get_url_domain(url1, sizeof(url1));
    const char* domain2 = get_url_domain(url2, sizeof(url2));
    const char* domain3 = get_url_domain(url3, sizeof(url3));

    printf("\nURL1域名:%s\n", domain1);
    printf("URL2域名:%s\n", domain2);
    printf("URL3域名:%s\n", domain3);

    return 0;
}

運(yùn)行結(jié)果

日志含敏感詞:badword

URL1域名:github.com
URL2域名:www.baidu.com
URL3域名:ftp://ftp.example.com

7. 注意事項(xiàng)

  • 雙長度參數(shù)需同步校驗(yàn)haystackszneedlesz均需包含各自的\0,如子串"abc"needlesz應(yīng)為4;
  • 子串為空的特殊處理:根據(jù) C11 標(biāo)準(zhǔn),若needle為空(""),result會(huì)返回主串起始位置(而非NULL);
  • 大小寫敏感strstr_s區(qū)分大小寫(如"ABC""abc"),如需不敏感匹配,需先將主串 / 子串統(tǒng)一轉(zhuǎn)為大寫 / 小寫;
  • 性能優(yōu)化:樸素算法在 “主串 / 子串均為 AAAAA...B” 時(shí)效率低,實(shí)際開發(fā)中可優(yōu)先使用標(biāo)準(zhǔn)庫實(shí)現(xiàn)(如 GCC 的strstr_s用 KMP 優(yōu)化)。

五、安全函數(shù)與傳統(tǒng)函數(shù)的差異對(duì)比

為清晰區(qū)分strchr_s/strrchr_s/strstr_s與傳統(tǒng)函數(shù),下表從核心特性維度對(duì)比:

對(duì)比維度strchr(傳統(tǒng))strchr_s(安全)strstr(傳統(tǒng))strstr_s(安全)
函數(shù)原型char* strchr(const char*, int)errno_t strchr_s(..., rsize_t, ..., **)char* strstr(const char*, const char*)errno_t strstr_s(..., rsize_t, ..., rsize_t, **)
返回值含義直接返回查找結(jié)果(指針 / NULL)返回錯(cuò)誤碼(0 = 成功),結(jié)果通過輸出參數(shù)獲取直接返回查找結(jié)果(指針 / NULL)返回錯(cuò)誤碼(0 = 成功),結(jié)果通過輸出參數(shù)獲取
長度參數(shù)無(依賴\0終止)有(strsz,強(qiáng)制邊界檢查)無(依賴\0終止)有(haystacksz+needlesz
錯(cuò)誤處理未定義(如空指針會(huì)崩潰)明確錯(cuò)誤碼(EINVAL/ESPACE)未定義(如子串未終止會(huì)越界)明確錯(cuò)誤碼(EINVAL/ESPACE/EILSEQ)
空指針處理程序崩潰或不可預(yù)測行為返回 EINVAL,result=NULL程序崩潰或不可預(yù)測行為返回 EINVAL,result=NULL
未終止字符串處理越界訪問(緩沖區(qū)溢出風(fēng)險(xiǎn))返回 ESPACE,拒絕處理越界訪問(緩沖區(qū)溢出風(fēng)險(xiǎn))返回 ESPACE,拒絕處理
適用場景信任輸入的簡單場景不可信輸入、安全關(guān)鍵場景信任輸入的簡單場景不可信輸入、安全關(guān)鍵場景
標(biāo)準(zhǔn)依賴C89 及以后(所有編譯器支持)C11 及以后(需定義__STDC_WANT_LIB_EXT1__C89 及以后(所有編譯器支持)C11 及以后(需定義__STDC_WANT_LIB_EXT1__

六、經(jīng)典面試題

??問:strchr_s在什么情況下會(huì)返回 EINVAL錯(cuò)誤?請(qǐng)列舉至少三種情況。??

??答:??

  1. 當(dāng) str參數(shù)為 NULL但 strsz不為 0 時(shí)
  2. 當(dāng) result輸出參數(shù)為 NULL指針時(shí)
  3. 當(dāng) strsz參數(shù)為 0 但 str不為 NULL時(shí)(部分實(shí)現(xiàn))
  4. 當(dāng)任何參數(shù)不滿足前置條件,如指針對(duì)齊問題等

 問:在處理網(wǎng)絡(luò)數(shù)據(jù)包時(shí),為什么 strstr_s比 strstr更安全?請(qǐng)從攻擊者角度分析。??

??答:?? 攻擊者可以構(gòu)造特殊數(shù)據(jù)包:

  • 發(fā)送不含 \0終止符的長字符串,導(dǎo)致 strstr越界讀取
  • 精心設(shè)計(jì)偏移使查找操作跨越緩沖區(qū)邊界
  • 利用越界讀取獲取敏感信息或?qū)е鲁绦虮罎?/li>

strstr_s通過 destsz和 srcsz雙重限制,確保搜索在預(yù)定邊界內(nèi)進(jìn)行,即使面對(duì)惡意數(shù)據(jù)也能安全處理。

問:如果項(xiàng)目需要同時(shí)支持 Windows 和 Linux,如何實(shí)現(xiàn)安全字符串函數(shù)的跨平臺(tái)兼容???

??答:?? 推薦三種方案:

  1. ??特性檢測宏??:使用 #ifdef __STDC_LIB_EXT1__檢測編譯器支持
  2. ??適配層封裝??:實(shí)現(xiàn)統(tǒng)一接口,底層調(diào)用平臺(tái)相關(guān)實(shí)現(xiàn)
  3. ??第三方庫??:引入 safeclib等跨平臺(tái)兼容庫

最佳實(shí)踐是創(chuàng)建項(xiàng)目內(nèi)的安全字符串包裝層,集中處理平臺(tái)差異,為業(yè)務(wù)代碼提供統(tǒng)一接口。

問:將傳統(tǒng)函數(shù)strchr的調(diào)用代碼遷移為strchr_s,需注意哪些關(guān)鍵步驟?請(qǐng)舉例說明。

:遷移需圍繞 “參數(shù)適配”“錯(cuò)誤處理”“結(jié)果獲取” 三個(gè)核心步驟,具體如下:

步驟 1:啟用 C11 安全函數(shù)

在包含<string.h>前定義宏__STDC_WANT_LIB_EXT1__,確保編譯器啟用安全接口:

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>

步驟 2:調(diào)整函數(shù)參數(shù)(新增長度參數(shù)與輸出參數(shù))

  • 傳統(tǒng)strchr調(diào)用:char* pos = strchr(str, 'a');
  • 安全strchr_s需新增:① 長度參數(shù)(strsz);② 輸出參數(shù)(result指針)。

步驟 3:新增錯(cuò)誤處理邏輯

傳統(tǒng)函數(shù)不返回錯(cuò)誤碼,遷移后需先校驗(yàn)err是否為0,再處理result(避免將 “參數(shù)錯(cuò)誤” 與 “未找到” 混淆)。

步驟 4:調(diào)整結(jié)果獲取方式

strchr_s的結(jié)果通過輸出參數(shù)result獲取,而非直接返回。

遷移示例(從strchrstrchr_s):

傳統(tǒng)代碼:

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

int main() {
    char str[] = "name:zhangsan";
    // 傳統(tǒng)調(diào)用:直接返回結(jié)果
    char* pos = strchr(str, ':');
    
    if (pos != NULL) {
        printf("找到':',后續(xù)內(nèi)容:%s\n", pos + 1);
    } else {
        printf("未找到':'\n");
    }
    return 0;
}

遷移后代碼

#define __STDC_WANT_LIB_EXT1__ 1  // 步驟1:啟用安全函數(shù)
#include <stdio.h>
#include <string.h>
#include <errno.h>  // 步驟1:包含錯(cuò)誤碼頭文件

int main() {
    char str[] = "name:zhangsan";
    const char* result;  // 步驟2:新增輸出參數(shù)
    errno_t err;         // 步驟2:新增錯(cuò)誤碼變量

    // 步驟2:調(diào)用strchr_s,新增長度參數(shù)sizeof(str)
    err = strchr_s(str, sizeof(str), ':', &result);

    // 步驟3:優(yōu)先處理錯(cuò)誤
    if (err != 0) {
        printf("查找錯(cuò)誤!錯(cuò)誤碼:%d\n", err);
        return 1;
    }

    // 步驟4:通過result獲取結(jié)果
    if (result != NULL) {
        printf("找到':',后續(xù)內(nèi)容:%s\n", result + 1);
    } else {
        printf("未找到':'\n");
    }
    return 0;
}

關(guān)鍵注意點(diǎn)

  • 長度參數(shù)必須包含\0(如sizeof(str)而非strlen(str));
  • 錯(cuò)誤碼err的校驗(yàn)優(yōu)先級(jí)高于result(如err=EINVAL時(shí)result也為NULL,但屬于參數(shù)錯(cuò)誤,需單獨(dú)處理)。

strchr_s、strrchr_sstrstr_s是 C11 標(biāo)準(zhǔn)為解決傳統(tǒng)字符串函數(shù)安全問題而設(shè)計(jì)的核心工具,它們通過 “強(qiáng)制長度參數(shù) + 明確錯(cuò)誤處理”,從根源上規(guī)避了緩沖區(qū)溢出等風(fēng)險(xiǎn)。

開發(fā)實(shí)踐中,需根據(jù)場景選擇函數(shù):

  • 簡單信任輸入場景:傳統(tǒng)函數(shù)(strchr等)更簡潔;
  • 不可信輸入(如用戶輸入、網(wǎng)絡(luò)數(shù)據(jù))或安全關(guān)鍵模塊:必須使用安全函數(shù)(strchr_s等)。

掌握安全函數(shù)的使用與遷移方法,不僅能提升代碼健壯性,更是 C 語言開發(fā)者應(yīng)對(duì)安全面試的核心考點(diǎn)。

以上就是C語言字符串安全查找的三種方式詳解的詳細(xì)內(nèi)容,更多關(guān)于C語言字符串安全查找的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++的深淺拷貝和寫時(shí)拷貝你了解嗎

    C++的深淺拷貝和寫時(shí)拷貝你了解嗎

    這篇文章主要為大家詳細(xì)介紹了C++的深淺拷貝和寫時(shí)拷貝,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C++中vector容器使用詳細(xì)說明

    C++中vector容器使用詳細(xì)說明

    在c++中,vector是一個(gè)十分有用的容器,下面通過本文給大家介紹C++中vector容器使用詳細(xì)說明,需要的朋友可以參考下
    2016-10-10
  • c語言實(shí)現(xiàn)向上取整計(jì)算方法

    c語言實(shí)現(xiàn)向上取整計(jì)算方法

    這篇文章主要介紹了c語言實(shí)現(xiàn)向上取整計(jì)算方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++實(shí)現(xiàn)航空訂票程序

    C++實(shí)現(xiàn)航空訂票程序

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)航空訂票程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++實(shí)現(xiàn)班車管理系統(tǒng)課程設(shè)計(jì)

    C++實(shí)現(xiàn)班車管理系統(tǒng)課程設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)班車管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++11中的包裝器實(shí)戰(zhàn)案例

    C++11中的包裝器實(shí)戰(zhàn)案例

    本文給大家介紹C++11中的包裝器實(shí)戰(zhàn)案例,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-11-11
  • 基于C語言實(shí)現(xiàn)簡單的五子棋游戲

    基于C語言實(shí)現(xiàn)簡單的五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了基于C語言實(shí)現(xiàn)簡單的五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Win10下最新版CLion(2020.1.3)安裝及環(huán)境配置教程詳解

    Win10下最新版CLion(2020.1.3)安裝及環(huán)境配置教程詳解

    這篇文章主要介紹了Win10下最新版CLion(2020.1.3)安裝及環(huán)境配置,CLion 是 JetBrains 推出的全新的 C/C++ 跨平臺(tái)集成開發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-08-08
  • QT線程池的使用(QThreadPool類和QRunnable類)

    QT線程池的使用(QThreadPool類和QRunnable類)

    本文主要介紹了QT線程池的使用(QThreadPool類和QRunnable類),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • C語言代碼 模塊化實(shí)現(xiàn)三子棋

    C語言代碼 模塊化實(shí)現(xiàn)三子棋

    這篇文章主要為大家詳細(xì)介紹了C語言 模塊化實(shí)現(xiàn)三子棋程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11

最新評(píng)論

卓资县| 临夏县| 资源县| 松阳县| 永善县| 基隆市| 喀喇沁旗| 宁城县| 芦山县| 恩平市| 揭阳市| 海门市| 兴国县| 扬中市| 德令哈市| 晋江市| 濮阳县| 景东| 永清县| 谢通门县| 曲周县| 深圳市| 汨罗市| 宜城市| 玉门市| 恭城| 义马市| 万山特区| 本溪| 康定县| 拜泉县| 阳原县| 桂东县| 安阳县| 滦南县| 驻马店市| 青冈县| 汝城县| 博爱县| 东山县| 阳泉市|