【C語言】字符函數和字符串函數

?

目錄

1.求字符串長度strlen

2.長度不受限制的字符串函數

字符串拷貝strcpy

字符串追加strcat

字符串比較strcmp

3.長度受限制的字符串函數介紹strncpy

strncat

?編輯strncmp

4.字符串查找strstr

5.字符串分割strtok

6.錯誤信息報告

strerror

perror

7.字符分類函數

8.字符轉換函數

?9.內存操作函數

memcpy

memmove

?memset

?memcmp?編輯


1.求字符串長度strlen

函數介紹

  • 字符串已經 '\0' 作為結束標志,strlen函數返回的是在字符串中 '\0' 前面出現的字符個數(不包含 '\0' )。
  • 參數指向的字符串必須要以 '\0' 結束。
  • 注意函數的返回值為size_t,是無符號的( 易錯 )?

使用示例

int main()
{size_t sz = strlen("abcd");printf("%u", sz);return 0;
}

因為函數的返回值為無符號類型,所以對于下面這種代碼,我們很容易就看錯:

#include<stdio.h>
#include<string.h>
int main()
{if (strlen("abc") - strlen("abcdef") > 0){printf("大于\n");}else{printf("小于\n");}return 0;
}

輸出結果:

?正確的比較方法:

if (strlen("abc") > strlen("abcdef"))

strlen的模擬實現

size_t my_strlen(const char* str)
{int count = 0;while (*str!='\0'){count++;str++;}return count;
}


2.長度不受限制的字符串函數

字符串拷貝strcpy

  • Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
  • 源字符串必須以 '\0' 結束。
  • 會將源字符串中的 '\0' 拷貝到目標空間。
  • 目標空間必須足夠大,以確保能存放源字符串。
  • 目標空間必須可變

使用示例

int main()
{char arr1[20] = { 0 };char arr2[] = "hello world";strcpy(arr1, arr2);printf("%s", arr1);return 0;
}

輸出結果:?

strcpy的模擬實現

char* my_strcpy(char* dest, const char* src)
{assert(dest && src);char* ret = dest;while (*dest++ = *src++){}return ret;
}

字符串追加strcat

  • ?Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
  • 源字符串必須以 '\0' 結束。
  • 目標空間必須有足夠的大,能容納下源字符串的內容。
  • 目標空間必須可修改。
  • 字符串自己給自己追加,如何?

?使用示例

int main()
{char arr1[20] = "hello ";char arr2[] = "world";strcat(arr1, arr2);printf("%s", arr1);return 0;
}

輸出結果:?

?strcat的模擬實現

char* my_strcat(char* dest, const char* src)
{assert(dest && src);char* ret = dest;while (*dest != '\0')//找到目標空間的\0{dest++;}while (*dest++ = *src++){}return ret;
}

注意:字符串不能自己給自己追加?

當字符串自己給自己追加時,字符串中的'\0'將會被覆蓋,導致程序陷入死循環。

字符串比較strcmp

  • ?This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
  • 標準規定:
  • 第一個字符串大于第二個字符串,則返回大于0的數字
  • 第一個字符串等于第二個字符串,則返回0
  • 第一個字符串小于第二個字符串,則返回小于0的數字

使用示例

int main()
{int ret1 = strcmp("abcdef", "abq");int ret2 = strcmp("abc", "abc");printf("%d\n", ret1);printf("%d\n", ret2);return 0;
}

?輸出結果:?

strcmp的模擬實現

int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1++ == *str2++){if (*str1 == '\0'){return 0;}}return *str1 - *str2;
}


3.長度受限制的字符串函數介紹
strncpy

  • Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
  • 拷貝num個字符從源字符串到目標空間。
  • 如果源字符串的長度小于num,則拷貝完源字符串之后,在目標的后邊追加0,直到num個。

使用示例

int main()
{char arr1[20] = "abcdef";char arr2[20] = "xxxxxxxxxxxxxx";strncpy(arr1, arr2, 3);printf("%s\n", arr1);return 0;
}

輸出結果:?

strncat

  • Appends the first num characters of source to destination, plus a terminating null-character.
  • If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.

使用示例

int main()
{char arr1[20] = "hello ";char arr2[20] = "worldxxx";strncat(arr1, arr2, 5);printf("%s\n", arr1);return 0;
}

輸出結果:?


strncmp

?比較到出現另個字符不一樣或者一個字符串結束或者num個字符全部比較完。

?使用示例

int main()
{char arr1[20] = "abc";char arr2[20] = "abcdef";char arr3[20] = "aba";printf("%d\n", strncmp(arr1, arr2, 3));printf("%d\n", strncmp(arr1, arr2, 4));printf("%d\n", strncmp(arr1, arr3, 5));return 0;
}

輸出結果:?


4.字符串查找strstr

strstr函數是在字符串str1中查找是否含有字符串str2,如果存在,返回str2在str1中第一次出現的地址;否則返回NULL。

使用示例

int main()
{char arr1[] = "abcdefabcdef";char arr2[] = "def";char* ret = strstr(arr1, arr2);if(ret!=NULL){printf("%s\n", ret);}return 0;
}

輸出結果:?

?strstr的模擬實現

這里使用的是BF算法來實現:

char* my_strstr(char* str1, char* str2)
{char* cp = str1;char* s1 = cp;char* s2 = str2;while (*cp){s1 = cp;s2 = str2;while (*s1 && *s2 && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')return cp;cp++;}return NULL;
}


5.字符串分割strtok

  • sep參數是個字符串,定義了用作分隔符的字符集合
  • 第一個參數指定一個字符串,它包含了0個或者多個由sep字符串中一個或者多個分隔符分割的標 記。
  • strtok函數找到str中的下一個標記,并將其用 \0 結尾,返回一個指向這個標記的指針。(注: strtok函數會改變被操作的字符串,所以在使用strtok函數切分的字符串一般都是臨時拷貝的內容并且可修改。)
  • strtok函數的第一個參數不為 NULL ,函數將找到str中第一個標記,strtok函數將保存它在字符串中的位置。
  • strtok函數的第一個參數為 NULL ,函數將在同一個字符串中被保存的位置開始,查找下一個標記。
  • 如果字符串中不存在更多的標記,則返回 NULL 指針。

使用示例1

int main()
{char arr[] = "123@qq.com";char sep[] = "@.";char copy[20];strcpy(copy, arr);char* pc = strtok(copy, sep);while (pc){puts(pc);pc = strtok(NULL, sep);}return 0;
}

使用示例2

int main()
{char arr[] = "123@qq.com";char sep[] = "@.";char copy[20];strcpy(copy, arr);char* ret = NULL;for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}return 0;
}

輸出結果:?

6.錯誤信息報告

strerror

?返回錯誤碼,所對應的錯誤信息。

庫函數在執行的時候,發生了錯誤會將錯誤碼存放在errno這個全局變量中。errno是C語言提供的一個全局變量。

下面代碼是將錯誤碼0~9所對應的錯誤信息給打印出來:

int main()
{int i = 0;for (int i = 0; i < 10; i++){printf("%d:%s\n", i, strerror(i));}return 0;
}

?當然,這里展示的僅僅是一小部分。

下面演示一下當我們進行文件操作是,打開文件失敗后查找打開失敗的原因:

int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){printf("%s\n", strerror(errno));}return 0;
}

程序輸出了“ No such file or directory ”的錯誤提示,意思是沒有要打開的文件。

perror

perror(str) 用來將上一個函數發生錯誤的原因輸出到標準設備(stderr)。參數 str 所指的字符串會先打印出,后面再加上錯誤原因字符串。此錯誤原因依照全局變量errno的值來決定要輸出的字符串。

使用示例

int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){printf("%s\n", strerror(errno));perror("fopen");}return 0;
}

?輸出結果:


7.字符分類函數

8.字符轉換函數

?下面代碼的功能是輸入一串字符,將字符串中的小寫字母轉成大寫,大寫字母轉成小寫

int main()
{char arr[30] = { 0 };gets(arr);char* p = arr;while (*p){if (isupper(*p)){*p = tolower(*p);}else if (islower(*p)){*p = toupper(*p);}*p++;}puts(arr);
}

?
9.內存操作函數

memcpy

  • 函數memcpy從source的位置開始向后復制num個字節的數據到destination的內存位置。
  • 這個函數在遇到 '\0' 的時候并不會停下來。
  • 如果source和destination有任何的重疊,復制的結果都是未定義的。

可以拷貝任意類型的數據:字符串,整形數組,結構體數據類型……

使用示例

int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };//將arr1的內容拷貝到arr2中memcpy(arr2, arr1, 40);for (int i = 0; i < 20; i++){printf("%d ", arr2[i]);}return 0;
}

?輸出結果:

?memcpy的模擬實現

void* my_memcpy(void* dest, void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}

注意下面這種寫法編譯器會報錯:

在代碼中,使用了(char*)dest++(char*)src++來更新指針的位置。然而,這種寫法是不正確的,因為后綴遞增操作符++的優先級高于類型轉換操作符(char*),所以實際上你只是在轉換指針類型后遞增了一個臨時變量,而沒有更新指針本身的值。

注意:mencpy 函數是用來處理不會重疊的內存拷貝,當我們拷貝兩個相同的字符串是,可以結果與預期的會不相同:

int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };my_memcpy(arr1+2, arr1, 32);for (int i = 0; i < 10; i++){printf("%d ", arr1[i]);}printf("\n");return 0;
}

對于上面的代碼,我們的預期結果是這樣的:

?實際輸出的結果卻是如下:

?如果要拷貝重疊的內存,我們就要使用下面這個函數了


memmove

  • 和memcpy的差別就是memmove函數處理的源內存塊和目標內存塊是可以重疊的。
  • 如果源空間和目標空間出現重疊,就得使用memmove函數處理。

使用示例

int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr1+2, arr1, 32);for (int i = 0; i < 10; i++){printf("%d ", arr1[i]);}printf("\n");return 0;
}

?輸出結果:

?memmove的模擬實現

不同于memcpy,mommove的拷貝需要分情況:

void* my_memmove(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;if (dest < src){//從前向后拷貝while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else{printf("從后向前拷貝\n");//從后向前拷貝while (num--){*((char*)dest + num) = *((char*)src + num);}}return ret;
}

?
memset

?memset是一個初始化函數,作用是將某一塊內存中的全部設置為指定的值。

  • prr 指向要填充的內存塊。
  • value 是要被設置的值。
  • num 是要被設置該值的字符數。
  • 返回類型是一個指向存儲區s的指針。

使用示例1

int main()
{char arr[] = "hello world";memset(arr + 1, 'x', 4);printf("%s\n", arr);return 0;
}

上面代碼的作用是將的arr數組的第2個元素到第5個元素的值設置成‘x',輸出結果:

使用示例2

int main()
{int arr[10] = { 0 };memset(arr, 1, 10);return 0;
}

?
memcmp

比較從ptr1和ptr2指針開始的num個字節

返回值如下:

?使用示例

int main()
{int arr1[] = { 1,2,1,4,5,6 };int arr2[] = { 1,2,257 };int ret = memcmp(arr1, arr2, 9);printf("%d\n", ret);return 0;
}

對于上面的代碼,可以借助編譯器的調試來查看 arr1 和 arr2 的內存:

可以看出,arr1和arr2的前9個字節是相同的,而我們比較的是前9個字節,因此輸出結果應該是0。?

?

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

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

相關文章

【算法挨揍日記】day03——雙指針算法_有效三角形的個數、和為s的兩個數字

611. 有效三角形的個數 611. 有效三角形的個數https://leetcode.cn/problems/valid-triangle-number/ 題目描述&#xff1a; 給定一個包含非負整數的數組 nums &#xff0c;返回其中可以組成三角形三條邊的三元組個數。 解題思路&#xff1a; 本題是一個關于三角形是否能成立…

淺談Fetch API

什么是Fetch API Fetch API 是一種現代的 JavaScript API&#xff0c;用于進行網絡請求和處理響應數據。它提供了一種更簡單和更靈活的方式來執行網絡請求&#xff0c;取代了傳統的 XMLHttpRequest&#xff08;XHR&#xff09;。 Fetch API 具有以下特點&#xff1a; Promise…

概述、搭建Redis服務器、部署LNP+Redis、創建Redis集群、連接集群、集群工作原理

Top NSD DBA DAY09 案例1&#xff1a;搭建redis服務器案例2&#xff1a;常用命令限案例3&#xff1a;部署LNPRedis案例4&#xff1a;創建redis集群 1 案例1&#xff1a;搭建redis服務器 1.1 具體要求如下 在主機redis64運行redis服務修改服務運行參數 ip 地址192.168.88.6…

【問題整理】Ubuntu 執行 apt-get install xxx 報錯

Ubuntu 執行 apt-get install xxx 報錯 一、問題描述: 執行apt-get install fcitx時&#xff0c;報如下錯誤 grub-pc E: Sub-process /usr/bin/dpkg returned an error code (1)二、解決方法: 嘗試修復依賴問題&#xff1a; sudo apt-get -f install這個命令會嘗試修復系統…

Elasticsearch:如何在 Ubuntu 上安裝多個節點的 Elasticsearch 集群 - 8.x

Elasticsearch 是一個強大且可擴展的搜索和分析引擎&#xff0c;可用于索引和搜索大量數據。 Elasticsearch 通常用于集群環境中&#xff0c;以提高性能、提供高可用性并實現數據冗余。 在本文中&#xff0c;我們將討論如何在 Ubuntu 20.04 上安裝和配置具有多節點集群的 Elast…

關于Linux Docker springboot jar 日志時間不正確 問題解決

使用Springboot項目的jar&#xff0c;制作了一個Docker鏡像&#xff0c;啟動該鏡像后發現容器和容器中的Springboot 項目的日志時間不正確。 解決 查看容器時間命令為&#xff1a; docker exec 容器id date 1. 容器與宿主機同步時間 在啟動鏡像時候把操作系統的時間通過&q…

SpringBoot創建和使用

spring core的方式來寫代碼還是比較繁瑣的&#xff0c;而spring boot就是幫助程序員使用spring開發的一個腳手架&#xff08;boot&#xff09;&#xff0c;它是一個用于構建Java應用程序的開源框架&#xff0c;旨在簡化開發流程并提高生產效率。它的主要優點有&#xff1a; 快速…

CSS簡介

目錄 CSS CSS概念 核心概念 為什么需要CSS 語法 CSS的引入方式 內聯樣式&#xff08;行內樣式&#xff09; 內部樣式 外部樣式&#xff08;推薦&#xff09; CSS CSS概念 CSS&#xff08;Cascading Style Sheets&#xff09;層疊樣式表&#xff0c;又叫級聯樣式表&am…

【Vue-Router】導航守衛

前置守衛 main.ts import { createApp } from vue import App from ./App.vue import {router} from ./router // import 引入 import ElementPlus from element-plus import element-plus/dist/index.css const app createApp(App) app.use(router) // use 注入 ElementPlu…

ShowMeBug CEO李亞飛受邀參加深圳青年創新創業系列沙龍電子信息專場

7月13日下午&#xff0c;由深圳市科技交流服務中心&#xff08;深圳市科技專家委員會辦公室&#xff09;主辦&#xff0c;深圳新一代產業園承辦的“2023深圳青年創新創業系列沙龍——電子信息專場”活動舉行。ShowMeBug CEO李亞飛受邀參加此次活動。 深圳市科學技術協會黨組成員…

微信小程序真機調試異常cmdId 1006, errCode-50011-已解決

cmdId 1006, errCode-50011 起因 小程序在模擬器上預覽沒問題,真機調試和體驗版首頁打不開,點展開顯示cmdId 1006, errCode-50011 解決 查了下1006, 說是廣告, 我沒接廣告,這個也不是錯誤碼 1006廣告組件被駁回你的廣告正在被審核,無法展現廣告后來找到幾個類似的帖子…

arm開發板 GDB遠程調試方法

1.前言 1.在linux下開發&#xff0c;免不了使用gdb調試&#xff0c;但是linux下開發嵌入式&#xff0c;都是跑在ARM板子上的&#xff0c;網上有很多GDB的基礎教程&#xff0c;但是能在ARM開發板用的時候&#xff0c;會有各種問題。 比如&#xff1a;*.cpp: No such file or di…

Android su

1. userdebug和user版本 2. 關閉selinux system/core diff --git a/init/selinux.cpp b/init/selinux.cpp index 5a0255acd..787917274 100644--- a/init/selinux.cpp b/init/selinux.cpp -104,6 104,8 EnforcingStatus StatusFromCmdline() { } bool IsEnforcing() { …

元宇宙時代超高清視音頻技術白皮書關于流媒體協議和媒體傳輸解讀

流媒體協議 元宇宙業務場景對流媒體傳輸的實時性和互動性提出了更高的要求&#xff0c;這就需要在傳統的 RTMP、SRT、 HLS 等基礎上增加實時互動的支持。實時互動&#xff0c;指在遠程條件下溝通、協作&#xff0c;可隨時隨地接入、實時地傳遞虛實融合的多維信息&#xff0c;身…

萬賓燃氣管網監測解決方案,守護城市生命線安全

方案背景 城市燃氣管網作為連接天然氣長輸管線與天然氣用戶的橋梁&#xff0c;擔負著向企業和居民用戶直接供氣的重要職責。隨著城市燃氣需求的急劇增加&#xff0c;城市燃氣管網規模日趨龐大&#xff0c;安全隱患和風險也隨之增加。目前&#xff0c;我國燃氣管網的運行仍存在…

Mathematica(42)-計算N個數值的和

比如&#xff0c;我們要用Mathematica求得到下面的式子&#xff1a; 這就需要用到一個函數&#xff1a;Sum 具體地&#xff0c;Sum函數的使用形式如下&#xff1a; 因此&#xff0c;按照公式就可以得到下面的結果&#xff1a; 如果&#xff0c;我們想要將求和號也加進去&#…

Jenkins的流水線啟動jar后未執行問題處理

現象 在流水線里配置了啟動腳本例如&#xff0c;nohup java -jar xxx.jar >nohup.out 2>&1 & 但是在服務器發現服務并未啟動,且nohup日志里沒輸出日志,這樣的原因是jenkins在執行完腳本后&#xff0c;就退出了這個進程。 在啟動腳本執行jar命令的上一步加入以下…

【AIGC 訊飛星火 | 百度AI|ChatGPT| 】智能對比

AI智能對比 &#x1f378; 前言&#x1f37a; 概念類對比&#x1f375; 訊飛&#x1f375; 百度AI&#x1f375; chatGPT &#x1f379; 功能類對比? 訊飛? 百度AI? chatGPT &#x1f943; 可輸入字數對比&#x1f964; 百度AI&#x1f964; 訊飛&#x1f964; chatGPT &…

【Django】Task1安裝python環境及運行項目

【Django】Task1安裝python環境及運行項目 寫在最前 8月份Datawhale組隊學習&#xff0c;在這個群除我佬的時代&#xff0c;寫一下blog記錄學習過程。 參考資源&#xff1a; 學習項目github&#xff1a;https://github.com/Joe-2002/sweettalk-django4.2 隊長博客&#xff1a…

RocketMQ 消息消費 輪詢機制 PullRequestHoldService

1. 概述 先來看看 RocketMQ 消費過程中的輪詢機制是啥。首先需要補充一點消費相關的前置知識。 1.1 消息消費方式 RocketMQ 支持多種消費方式&#xff0c;包括 Push 模式和 Pull 模式 Pull 模式&#xff1a;用戶自己進行消息的拉取和消費進度的更新Push 模式&#xff1a;Broker…