一万字带你详解C语言字符函数字符串函数内存函数

Posted 跳动的bit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一万字带你详解C语言字符函数字符串函数内存函数相关的知识,希望对你有一定的参考价值。

🍳 前言

C语言对于字符和字符串的处理是很频繁的,但是C语言本身没有字符串类型,字符串通常放在常量字符串或者字符数组中。

一、求字符串长度

💦 strlen

🔗 函数原型和头:
在这里插入图片描述
🔗 函数的返回值:

在这里插入图片描述

🔗 功能:
在这里插入图片描述


#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abc";
	char arr2[] = { 'a', 'b', 'c' };
	printf("arr1的长度是:%d\\n", strlen(arr1));
	printf("arr2的长度是:%d\\n", strlen(arr2));
	return 0;
} 

输出结果:
在这里插入图片描述
📝 分析结果:
  ▶ “abc” 这种类型的字符串有4个元素 - > ‘a’ ‘b’ ‘c’ ‘\\0’
  这里说明了strlen这个函数在求字符串长度时计算的是 ‘\\0’ 之前的字符,且以 ‘\\0’ 为字符串的结束标志
  ▶ { ‘a’, ‘b’, ‘c’ } 这种类型的字符串只有3个元素 -> ‘a’, ‘b’, ‘c’
  这里的结果是一个随机数,因为字符串里并没有 ‘\\0’ 作为结束标志,所以它会继续往下数


❓ 观察以下代码,输出的结果是什么

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

输出结果:
在这里插入图片描述
📝 分析结果:

在这里插入图片描述
strlen函数的返回值类型无符号的


💨 总结:
▶ 字符串以 ‘\\0’ 作为结束标志,strlen函数的返回值是在字符串中 ‘\\0’ 前面出现的字符个数(不包含 ‘\\0’ )
▶ 参数指向的字符必须要以 ‘\\0’ 结束
▶ 注意函数的返回值为size_t,是无符号的(易错)

二、长度不受限制的字符串函数

💦 strcpy

🔗 函数原型和头:
在这里插入图片描述
🔗 函数的返回值:
在这里插入图片描述

🔗 功能:
在这里插入图片描述


#include<stdio.h>
int main()
{
	char arr[20] = { 0 };
	strcpy(arr, "hello");
	printf("%s\\n", arr);
	return 0;
}

⭕ 输出结果:hello
📝 分析结果:strcpy会把源字符串中的内容拷贝到目标空间,并返回目标空间的起始位置


❓ strcpy在拷贝的过程中是以 ‘\\0’ 为结束标志吗

📐 验证如下

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "##########";
	char arr2[] = "ab\\0cdef";
	strcpy(arr1, arr2);
	return 0;
}

⭕ 结果:
在这里插入图片描述

📝 分析:
strcpy在拷贝字符串时是以’\\0’为标志的,且会将’\\0’也拷贝


❓ 当原字符串要拷贝的空间比目标字符串的空间大时

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[5] = { 0 };
	char* p = "hello world";
	strcpy(arr, p);
	printf("%s\\n", arr);
	return 0;
}

⭕ 结果:
在这里插入图片描述


❓ 目标空间为常量字符串时

#include<stdio.h>
#include<string.h>
int main()
{
	char* str = "xxxxxxxxxx";
	char* p = "hello world";
	strcpy(str, p);
	printf("%s\\n", str);
	return 0;
}

⭕ 结果:
在这里插入图片描述


💨 总结:
▶ 源字符串必须以 ‘\\0’ 结束
▶ strcpy在拷贝的过程中是以 ‘\\0’ 为结束标志,且会将 ‘\\0’ 也拷贝
▶ 目标空间必须足够大,以确保能存放源字符串
▶ 目标空间必须可变

💦 strcat

🔗 函数原型和头:
在这里插入图片描述
🔗 函数的返回值:
在这里插入图片描述

🔗 功能:
在这里插入图片描述


#include<stdio.h>
int main()
{
	char arr1[20] = "hello";
	char arr2[] = "bit";
	strcat(arr1, arr2);
	printf("%s\\n", arr1);
	return 0;
}

⭕ 输出结果:
在这里插入图片描述
📝 分析结果:
从结果可以知道源字符串在追加时会找到目标字符串最后的 ‘\\0’ 并将它给覆盖,然后开始追加


❓ 在源字符串追加给目标字符串时,源字符串的 ‘\\0’ 会不会也追加

📐 验证如下

#include<stdio.h>
int main()
{
	char arr1[20] = "hello\\0xxxxxxxxxx";
	char arr2[] = "bit";
	strcat(arr1, arr2);
	printf("%s\\n", arr1);
	return 0;
}

结果:
在这里插入图片描述


❓ strcat能不能自己给自己追加

#include<stdio.h>
int main()
{
	char arr[20] = "abcd";
	strcat(arr, arr);//?
	printf("%s\\n", arr);
	return 0;
}

结果:

在这里插入图片描述
📝 分析:
在这里插入图片描述


💨 总结:
▶ 源字符串必须以 ‘\\0’ 结束
▶ 目标空间必须足够大,以足以容纳字符串
▶ 目标字符串必须可修改
▶ 不能自己追加自己

💦 strcmp

🔗 函数原型和头:
在这里插入图片描述
🔗 函数的返回值:
在这里插入图片描述

🔗 功能:
在这里插入图片描述


❌ 字符串的比较

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "def";
	char* p2 = "abc";
	if(p1 > p2)
		printf(">\\n");
	else 
		printf("<\\n");
	return 0;
}

📝 分析:
在这里插入图片描述


✔ 字符串的比较

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "def";
	char* p2 = "abcdef";
	printf("%d\\n", strcmp(p1, p2));
	return 0;
}

📝 分析:
在这里插入图片描述

三、长度受限制的字符串函数

💦 strncpy

🔗 函数原型和头:
在这里插入图片描述

🔗 函数的返回值:
在这里插入图片描述
🔗 功能:
在这里插入图片描述


#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "qwer";
	strncpy(arr1, arr2, 2);
	printf("%s\\n", arr1);
	return 0;
}

结果:
在这里插入图片描述


❓ 当指定的个数num大于源字符串时

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "qwe";
	strncpy(arr1, arr2, 6);
	printf("%s\\n", arr1);
	return 0;
}

结果:
在这里插入图片描述


💨 总结:
▶ 拷贝num个字符从源字符串到目标空间
▶ 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后面追加0,直到num个

💦 strncat

🔗 函数原型和头:
在这里插入图片描述

🔗 函数的返回值:
在这里插入图片描述
🔗 功能:
在这里插入图片描述


#include<stdio.h.>
#include<string.h>
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	strncat(arr1, arr2, 3);
	printf("%s\\n", arr1);
	return 0;
}

结果:
在这里插入图片描述


❓ strncat能否自己给自己追加

#include<stdio.h.>
#include<string.h>
int main()
{
	char arr1[20] = "hello";
	strncat(arr1, arr1, 6);
	printf("%s\\n", arr1);
	return 0;
}

结果和分析:
在这里插入图片描述

💦 strncmp

🔗 函数原型和头:
在这里插入图片描述

🔗 函数的返回值:
在这里插入图片描述
🔗 功能:
在这里插入图片描述


#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "abcdef";
	char* p2 = "abcpdf";
	int ret = strncmp(p1, p2, 4);
	printf("%d\\n", ret);
	return 0;
}

结果:
在这里插入图片描述

四、字符串查找

💦 strstr

🔗 函数原型和头:
在这里插入图片描述
🔗 函数的返回值:
在这里插入图片描述
🔗 功能:
在这里插入图片描述


#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdefabcdef";
	char arr2[] = "bcd";
	char* ret = strstr(arr1, arr2);
	if(ret == NULL)
		printf("没找到\\n");
	else
		printf("找到了:%s\\n", ret);
	return 0;
}

结果:
在这里插入图片描述
📝 分析:
strstr在目标字符串中查找子串,如果找到了就返回目标字符串中首次出现的源字符串的地址,否则返回一个空指针

💦 strtok

🔗 函数原型和头:
在这里插入图片描述

🔗 函数的返回值:
在这里插入图 片描述

🔗 功能:
在这里插入图片描述

🔗 函数详解:
▶ strDelimit的参数是一个字符串,定义了用作分隔符的字符集合
▶ strToken指定一个字符串,它包含了0个或者多个由strDelimit串中一个或者多个分隔符分割的标记
▶ strtok函数找到strToken中的下一个标记,并将其用 \\0 结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
▶ strtok函数的第一个参数不为NULL,函数将找到strToken中的第一个标记,strtok函数将保存它在字符串中的位置
▶ strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记
▶ 如果字符串中不存在更多的标记,则返回NULL指针
▶ strtok函数被调用一次,只会切割一次,所以想要切割多次,就需要多次调用


#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "wanghong@deboke.csdn";
	char* p = "@.";
	char temp[30] = { 0 };//拷贝一份arr于temp,让temp去切割
	strcpy(temp, arr);
	char* ret = NULL;

	ret = strtok(temp, p);
	printf("%s\\n", ret);
	
	ret = strtok(NULL, p);
	printf("%s\\n", ret);
	
	ret = strtok(NULL, p);
	printf("%s\\n", ret);
	
	return 0;
}

结果与分析:
在这里插入图片描述


但是我们通常会将多次分割的这个操作使用循环来实现,非常的妙啊 !!!

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "wanghong@deboke.csdn";
	char* p = "@.";
	char temp[30] = { 0 };
	strcpy(temp, arr);
	char* ret = NULL;
	
	for(ret = strtok(temp, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\\n", ret);
	}
	return 0;
}

五、错误信息报告

💦 strerror

🔗 函数原型和头:
在这里插入图片描述

🔗 函数的返回值:在这里插入图片描述

🔗 功能:
在这里插入图片描述

🔗 函数详解:
在调用库函数失败时,都会设置错误码
C语言中有一个全局的错误码 -> int errno ,只要调用库函数发生了错误,就会把错误码放到errno里去
这里strerror就会把错误码翻译成对应的错误信息,然后再把错误信息以字符串首地址返回回来
通常strerror都会和errno一起使用
使用errno需要头文件errno.h


#include<stdio.h>
#include<string.h>
int main()
{
	printf("%s\\n", strerror(0));
	printf("%s\\n", strerror(1));
	printf("%s\\n", strerror(2));
	printf("%s\\n", strerror(3));
	printf("%s\\n", strerror(4));
	printf("%s\\n", strerror(5));
	return 0;
}

结果与分析:

在这里插入图片描述


❓ 具体是怎么用的
注:以下所使用的对文件操作的一些函数会在后面进行了解

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	//以读的形式打开test.txt文件,这个文件如果不存在就会打开失败,然后返回一个空指针
	FILE* pf = fopen("test.txt", "r");
	//失败就输出失败的原因,也就题错误信息
	if(pf == NULL)
	{
		printf("%s\\n", strerror(errno));								
		return 1;
	}
	//...
	fclose(pf);//关闭文件
	pf == NULL;
	
	return 0;
}

结果:
在这里插入图片描述


💦 perror

🔗 函数原型和头:
在这里插入图片描述

🔗 函数的返回值:在这里插入图片描述

🔗 功能:
在这里插入图片描述


#include<stdio.h>
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if(pf == NULL)
	{
		perror("fopen");		
		return 1;
	}以上是关于一万字带你详解C语言字符函数字符串函数内存函数的主要内容,如果未能解决你的问题,请参考以下文章

小曾带你深入浅出机器学习(小白入门必备,近3万字带你了解机器学习)

密码学一万字带您走进密码学的世界(上)

密码学一万字带您走进密码学的世界(下)

C语言进阶—— 字符操作函数+内存操作函数详解 (吐血爆肝 !!!)

C语言进阶学习笔记三字符串函数+内存函数详解

硬核两万字带你理解C++之多态