C語言再學習25——常用字符串函數歸納

前言:

爲了方便查看博客,特意申請了一個公衆號,附上二維碼,有興趣的朋友可以關注,和我一起討論學習,一起享受技術,一起成長。

在這裏插入圖片描述


1. memcpy

內存複製函數。

1.1 頭文件

#include <string.h>

1.2 描述

void *memcpy(void *str1, const void *str2, size_t n) ;

從存儲區 str2 複製 n 個字符到存儲區 str1。

1.3 參數

str1: 指向用於存儲複製內容的目標數組,類型強制轉換爲 void* 指針;

str2: 指向要複製的數據源,類型強制轉換爲 void* 指針;

n: 要被複制的字節數。

1.4 返回值

該函數返回一個指向目標存儲區 str1 的指針。

1.5 注意

(1)複製的內容不同。strcpy 只能複製字符串,而 memcpy 可以複製任意內容,例如字符數組、整型、結構體、類等;

(2)複製的方法不同。strcpy 不需要指定長度,它遇到被複制字符的串結束符 “\0” 才結束,所以容易溢出。memcpy 則是根據其第 3 個參數決定複製的長度;

(3)用途不同。通常在複製字符串時用 strcpy,而需要複製其他類型數據時則一般用 memcpy。

(4)str1指針要分配足夠的空間,也即大於等於 n 字節的空間。如果沒有分配空間,會出現斷錯誤,造成空間溢出;

(5)str1 和 str2 所指的內存空間不能重疊(如果發生了重疊,使用 memmove() 會更加安全);

(6)memcpy 是按照字節進行拷貝。多字節數據的拷貝如下:

測試:

void memcpy_test(void)
{
	char src_buf[5] = {1, 2, 3, 4, 5};
	char dst_buf[10] = {0};
	int test_buf1[5] = {99, 8522, 987, 3467, 11027};
	int test_buf2[5] = {0};
	
	memcpy(dst_buf, src_buf, sizeof(src_buf));
	for (int i = 0; i < sizeof(src_buf); i++)
	{
		printf("dst_buf: %d \r\n", dst_buf[i]);
	}
	
	memcpy(test_buf2, test_buf1, sizeof(test_buf1));	//sizeof(test_buf1) = 20字節
	for (int i = 0; i < 5; i++)
	{
		printf("test_buf2: %d \r\n", test_buf2[i]);
	}
}

結果輸出:

在這裏插入圖片描述

1.6 原型實現

void *Memcpy(void *dest, const void *src, unsigned int count)
{
	char *pdest = (char *)dest;
	char *psrc = (char *)src;

	if (pdest == NULL || psrc == NULL)
	{
		return NULL;
	}

	if (pdest == psrc)
	{
		return;
	}

	if (pdest > psrc)
	{
		while (count--)
		{
			*(pdest + count) = *(psrc + count);
		}
	}
	else
	{
		while (count--)
		{
			*pdest++ = *psrc++;
		}
	}
	return pdest;
}

2. memset

將某一塊內存中的內容全部設置爲指定的值,它是對較大的結構體或數組進行清零操作的一種快捷方法。

2.1 頭文件

#include <string.h>

2.2 描述

void *memset(void *str, int c, size_t n) ;

複製字符 c(一個無符號字符)到參數 str 所指向的字符串的前 n 個字符。

2.3 參數

str: 指向要填充的內存塊

c: 要被設置的值。該值以 int 形式傳遞,但是函數在填充內存塊時是使用該值的無符號字符形式;

n: 要被設置爲該值的字節數。

2.4 返回值

該函數返回一個指向存儲區 str 的指針。

2.5 注意

(1)memset 函數按字節對內存塊進行初始化,所以不能用它將 int 數組初始化爲 0 和 -1 之外的其他值(除非該值高字節和低字節相同);

(2)memset(void *str, int c, size_t n) 中 c 實際範圍應該在 0——255,因爲該函數只能取 c 的後八位賦值給你所輸入的範圍的每個字節。無論 c 多大隻有後八位二進制有效,而後八位二進制的範圍在(0~255)。而對字符數組操作時則取後八位賦值給字符數組,其八位值作爲 ASCII 碼。

測試:

void memset_test(void)
{
	char test_buf1[5];
	int test_buf2[5];
	
	memset(test_buf1, 1, sizeof(test_buf1));
	memset(test_buf2, 1, sizeof(test_buf2));
	for (int i = 0; i < sizeof(test_buf1); i++)
	{
		printf("tset_buf1 is %x \r\n", test_buf1[i]);
	}
	for (int i = 0; i < 5; i++)
	{
		printf("tset_buf2 is %x \r\n", test_buf2[i]);
	}
}

結果輸出:

在這裏插入圖片描述

2.6 原型實現


void *MyMemset(void *dest, int n, unsigned int len)
{
	if (dest == NULL)
		return NULL;
	char *pdest = (char *)dest;
	while (len--)
	{
		*pdest++ = n;
	}

	return dest;
}

3. memcmp

把存儲區 str1 和存儲區 str2 的前 n 個字節進行比較,按字節比較

3.1 頭文件

#include <string.h>

3.2 描述

int memcmp(const void *str1, const void *str2, size_t n) ;

存儲區 str1 和存儲區 str2 的前 n 個字節進行比較。

3.3 參數

str1: 指向內存塊的指針;

str2: 指向內存塊的指針;

n: 要被比較的字節數。

3.4 返回值

如果返回值 < 0,則表示 str1 小於 str2;

如果返回值 > 0,則表示 str2 小於 str1;

如果返回值 = 0,則表示 str1 等於 str2。

3.5 注意

(1)該函數是按字節比較的,比較 str1 和 str2 的第一個字節的 ascII 碼值。

測試:

void memcmp_test(void)
{
	char str1[] = "abcd";
	char str2[] = "abcd";
	int ret = 0;

	ret = My_Memcmp(str1, str2, 4);
	printf("ret val is %d \r\n", ret);

	memcpy(str1, "abce", 4);
	ret = My_Memcmp(str1, str2, 4);
	printf("ret val is %d \r\n", ret);

	memcpy(str1, "abcc", 4);
	ret = My_Memcmp(str1, str2, 4);
	printf("ret val is %d \r\n", ret);
}

結果輸出:

在這裏插入圖片描述

3.6 原型實現

int My_Memcmp(void *str1, void *str2, int count)
{
	char *ptr1 = (char *)str1;
	char *ptr2 = (char *)str2;

	if (!count)
	{
		return 0;
	}

	while (count--)
	{
		if (*ptr1 == *ptr2)
		{
			ptr1 = ptr1 + 1;
			ptr2 = ptr2 + 1;
		}
		else
		{
			return *ptr1 - *ptr2;
		}
	}
	return *ptr1 - *ptr2;
}

4. strlen

strlen 所作的是一個計數器的工作,它從內存的某個位置(可以是字符串開頭,中間某個位置,甚至是某個不確定的內存區域)開始掃描,直到碰到第一個字符串結束符 ‘\0’ 爲止,然後返回字符計數器值(長度不包含 '\0 ')。

4.1 頭文件

#include <string.h>

4.2 描述

size_t strlen(const char *str) ;

計算字符串 str 的長度,直到空結束字符,但不包括空結束字符。

4.3 參數

str: 要計算長度的字符串。

4.4 返回值

該函數返回字符串的長度。

4.5 注意

(1)注意 strlen 和 sizeof 的區別。

測試:

void strlen_test(void)
{
	char *ptr = "asdfghjl";
	
	printf("strlen length is %d \r\n", strlen(ptr));
}

結果輸出:

在這裏插入圖片描述
輸出字符串長度不包括 ‘\0’。

4.6 原型實現

unsigned int My_Strlen(const char *str)
{
	int str_len = 0;

	while (*str++ != '\0')
	{
		str_len++;
	}
	return str_len;
}

5. strcpy

strcpy 把含有 ‘\0’ 結束符的字符串複製到另一個地址空間,返回值的類型爲 char*。

5.1 頭文件

#include <string.h>

5.2 描述

char *strcpy(char *dest, const char *src);

把 src 所指向的字符串複製到 dest。

5.3 參數

dest: 指向用於存儲複製內容的目標數組。;

src: 要複製的字符串。

5.4 返回值

該函數返回一個指向最終的目標字符串 dest 的指針。

5.5 注意

(1)若目標數組 dest 不夠大,而源字符串的長度又太長,可能會造成緩衝溢出的情況;

(2)src 和 dest 所指內存區域不可以重疊。

測試:

void strcpy_test(void)
{
	char test_buf1[6] = "ABCDE";
	char test_buf2[100] = {0};
	
	strcpy(test_buf2, test_buf1);
	printf("strcpy test %s \r\n", test_buf2);
}

5.6 原型實現

char *My_Strcpy(char *dest, const char *src)
{
	char *tmp = (char *)dest;
	
	if ((dest == NULL) || (src == NULL))
	{
		return 0;
	}
	
	while (*src != '\0')
	{
		*tmp++ = *src++;
	}
	*tmp = '\0';
	
	return tmp;
}

6. strcmp

比較兩個字符串並根據比較結果返回整數。基本形式爲 strcmp(str1, str2),若 str1 = str2,則返回零;若 str1 < str2,則返回負數;若 str1 > str2,則返回正數。

6.1 頭文件

#include <string.h>

6.2 描述

int strcmp(const char *str1, const char *str2);

把 str1 所指向的字符串和 str2 所指向的字符串進行比較。

6.3 參數

str1: 要進行比較的第一個字符串;

str2: 要進行比較的第二個字符串。

6.4 返回值

如果返回值小於 0,則表示 str1 小於 str2;

如果返回值大於 0,則表示 str1 大於 str2;

如果返回值等於 0,則表示 str1 等於 str2。

6.5 注意

(1)兩個字符串自左向右逐個字符相比(按 ASCII 值大小相比較),直到出現不同的字符或遇 ‘\0’ 爲止;

(2)只能比較字符串,即可用於比較兩個字符串常量或比較數組,不能比較數字等其他形式的參數。

測試:

void strcmp_test(void)
{
	int ret = 0;
//	char test_buf1[6] = "ABCBE";
//	char test_buf2[3] = "AB";
	char test_buf1[6] = {1, 2, 3, 4, 5, 6};
	char test_buf2[6] = {1, 2, 3, 7, 5, 6};
	
	ret = My_Strcmp(test_buf1, test_buf2);
	printf("ret val is %d \r\n", ret);
}

6.6 原型實現

int My_Strcmp(const char *str1, const char *str2)
{
	if (str1 == NULL || str2 == NULL)
	{
		return NULL;
	}
	
	while (*str1 == *str2)
	{
		str1++;
		str2++;
		
		if (*str1 == '\0' || *str2 == '\0')
		{
			break;
		}
	}
	
	return *str1 - *str2;
}

7. sprintf

字符串格式化命令。函數聲明爲 int sprintf(char *string, char *format [,argument,…]);,主要功能是把格式化的數據寫入某個字符串中,即發送格式化輸出到 string 所指向的字符串。

7.1 頭文件

#include <stdio.h>

7.2 描述

int sprintf(char *str, const char *format, ...);

發送格式化輸出到 str 所指向的字符串。

7.3 參數

str: 指向一個字符數組的指針,該數組存儲了 C 字符串;

format : 字符串,包含了要被寫入到字符串 str 的文本。它可以包含嵌入的 format 標籤,format 標籤可被隨後的附加參數中指定的值替換,並按需求進行格式化。format 標籤屬性是 %[flags] [width] [.precision] [length]specifier,具體介紹如下:

flags(標識):

在這裏插入圖片描述

width(寬度):

在這裏插入圖片描述

.precision(精度):

在這裏插入圖片描述

length(長度):

在這裏插入圖片描述

specifier(說明符):

在這裏插入圖片描述

附加參數 – 根據不同的 format 字符串,函數可能需要一系列的附加參數,每個參數包含了一個要被插入的值,替換了 format 參數中指定的每個 % 標籤。參數的個數應與 % 標籤的個數相同。

7.4 返回值

如果成功,則返回寫入的字符總數,不包括字符串追加在字符串末尾的空字符。如果失敗,則返回一個負數。

7.5 注意

(1)格式化數字字符串 sprintf 最常見的應用之一是把整數打印到字符串中;

(2)sprintf 的返回值是字符數組中字符的個數,即字符串的長度,不用在調用 strlen(str) 求字符串的長度;

測試:

void sprintf_test(void)
{
	char buf[100] = {0};
	double data = 3.141593;
	uint16_t len = 0;
	uint8_t test_buff[5] = {55, 22, 66, 77, 99};
	
	len = sprintf((char *)buf, "%f", data);
	printf("----------------------------------------------------------------- \r\n");
	printf("buf is %s \r\n", buf);
	printf("sprintf return len is %d \r\n", len);
	
	len = 0;
	
	for (uint16_t i = 0; i < sizeof(test_buff); i++)
	{
		len += sprintf((char *)buf + i * 2, "%d", test_buff[i]);	//數組數據轉換爲字符串
	}
	printf("test_buff val is %s \r\n", buf);
	printf("sprintf return len is %d \r\n", len);
	printf("----------------------------------------------------------------- \r\n");
}

結果輸出:
在這裏插入圖片描述


參考:

  1. C 庫函數
  2. Cplusplus.com
  3. memcpy
  4. (C語言)memcpy函數原型的實現
  5. C函數庫中的memcmp實現
  6. strlen (C/C++語言函數)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章