什么是字符串?我用一篇博文告诉你。

什么是字符串?我用一篇博文告诉你

    • 前言
    • 1.什么是字符串
      • 1.字符串的几种定义格式
        • 1.和整型数组一样
        • 2.上面的改进型
        • 3.一般用char *pcdata = "hello";
        • 4.第2和第3的区别
        • 5.'\0'的作用:
        • 6.程序整合代码
    • 2.字符串和整型数组在存储上的区别
      • 1.回忆如何计算数组的大小及数组元素的个数
      • 2.字符串的存储方式——多了结束标志'\0';
      • 3.程序代码
    • 3.sizeof 和 strlen 的区别
      • 1.编程案例
    • 4.动态开辟字符串
      • 1.malloc 函数
        • 1.函数原型
        • 2.解释
      • 2.realloc 函数
        • 1.函数原型
        • 2.解释
      • 3.strcpy函数
        • 1.函数原型
        • 2.解释
      • 4.free函数
        • 1.函数原型
        • 2.解释
        • 3.作用
      • 5.memset函数
        • 1.函数原型
        • 2.解释
      • 6.程序整合代码
    • 5.字符串几种常用的API
      • 1.输出字符串
      • 2.获取字符串
        • 1.gets函数
        • 2.scanf("%s",p);
      • 3.输入输出字符串程序
      • 4.自己实现字符串拷贝函数
        • 1.预备知识一:指针函数
        • 2.预备知识二:指针偏移*dest++ = *src++;
        • 3.[注:预备知识不知道的同学,可以看我写的指针博文——点击](https://blog.csdn.net/CallmeBrotherMa/article/details/131329475?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168872327716800184172692%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168872327716800184172692&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-131329475-null-null.142%5Ev88%5Econtrol_2,239%5Ev2%5Einsert_chatgpt&utm_term=C%E8%AF%AD%E8%A8%80%E6%8C%87%E9%92%88%E9%9A%BE%E5%90%97%EF%BC%9F%EF%BC%9F%EF%BC%9F%E6%88%91%E7%94%A8%E5%85%A8%E7%BD%91%E6%9C%80%E5%85%A8%E7%9A%84%E6%8C%87%E9%92%88%E7%9F%A5%E8%AF%86%E5%91%8A%E8%AF%89%E4%BD%A0%E3%80%82%E5%AE%83%E4%B8%8D%E9%9A%BE%EF%BC%81%EF%BC%81%EF%BC%81&spm=1018.2226.3001.4187)
        • 4.程序代码
      • 5.C语言断言函数assert
        • 1.原理和if...else一样
        • 2.定义1
        • 3.定义2
        • 4.程序终止现象为
        • 5.程序代码
      • 6.字符串拼接函数strcat
        • 1.定义
        • 2.使用strcat函数程序代码
        • 3.实现strcat函数程序代码
      • 7.字符串比较函数strcmp
        • 1.定义
          • 2.使用strcmp函数代码
        • 3.实现strcmp函数代码
    • 6.结束语

前言

  本篇博文是本人在学习嵌入式软件C语言中字符串章节的笔记,适用于小白入门C语言的同学。希望能帮到大家。有什么不足可以评论告诉我。
  在阅读本篇博文时,想学习的同学可以打打博文中的代码,甚至默写代码,改写代码,有助于你的学习。C语言注重多打代码,多练习,才能学得扎实。

1.什么是字符串

  1.字符串就是字符数组,但不是意义上的数组。

1.字符串的几种定义格式

1.和整型数组一样
int data[] = {1,2,3,4,5};  //整型数组
char str[] = {'a','b','c','d','e'};  //字符数组
2.上面的改进型
char str[] = "abcde"; //注意在这个字符串中系统默认在最后一个元素后面添加了一个字符串结束标志‘\0’
3.一般用char *pcdata = “hello”;
char *pcdata = "hello";

  1.如何理解char 芯pcdata = “hello”;
  char *pcdata = “hello”; //字符串常量,不允许修改。定义一个指针指向字符串。
  这段代码 char *pcdata = “hello”; 是一种字符串字面量的赋值方式,它的实际含义是将一个指向字符的指针变量 pcdata 指向了一个字符数组的首地址,而这个字符数组存储了字符串常量
“hello” 的内容。
  具体的实现过程是这样的,编译器会在全局数据区分配一块内存空间,并把 “hello” 这个字符串常量的内容存储在这个空间里。然后,编译器会将这个字符串常量所在的内存地址赋值给pcdata 指针变量,因此 pcdata 指针变量指向了这个字符串常量在内存中的起始地址。
  需要注意的是,在这种赋值方式下,字符串常量存储在静态区,不允许进行修改,因为这里指针指向的是一个常量地址。如果想修改字符串内容,需要使用 char 类型的数组或者 malloc 等函数分配的动态内存。而且也不建议使用 char *pcdata = “hello”; 的方式进行指针初始化,因为这是一个不安全的写法,容易导致内存泄漏问题。

4.第2和第3的区别

  1.二是字符串变量
  2.三是字符串常量——不予被修改
  3.注意指针的操作
  一、保存地址可以,修改指向,指向字符串常量地址空间。
  二、对野指针的内容空间操作不行

5.'\0’的作用:

  char cdata[] = {‘h’,‘e’,‘l’,‘l’,‘o’,‘\0’};
  在C语言中,"\0"表示字符串的结束符或空字符。它是一个特殊的字符常量,其ASCII值为0。在以null-terminated strin(以空字符结尾的字符串)表示的字符串中,\0用于标识字符串的结束位置。当程序遇到字符串中的\0时,它会认定该字符为字符串的结尾,并停止对该字符串的处理。这样的字符串在C语言中被视为有效的字符串表示方式。

6.程序整合代码
#include 
/*
   时间      2023年6月20日23:23:37
   程序功能:初识字符串
*/

int main()
{
	char cdata[] = {'h','e','l','l','o','\0'};//字符串常量允许修改
	char cdata2[] = "hello";//字符串常量允许修改
	char *pcdata = "hello"; //字符串常量,不允许修改。定义一个指针指向字符串
	int i;
	int size;
	int size2;
	
	/*
	char *p; //野指针,并没有明确的内存指向,危险
	*p = 'a'; //对野指针赋值会出现段错误。
	*/
	
	puts("程序功能:初识字符串");
	
    cdata[4] = 'e';  //字符串常量允许修改
	cdata2[4] = 'e'; //字符串常量允许修改
	
	size = sizeof(cdata)/sizeof(cdata[0]);
	size2 = sizeof(cdata2)/sizeof(cdata2[0]);
	puts("用for循环遍历字符串1");
	for(i=0; i<size; i++)
	{
		printf("%c",cdata[i]);
	}
	puts("\n用for循环遍历字符串2");
	for(i=0; i<size2; i++)
	{
		printf("%c",cdata2[i]);
	}
	puts("\n用for循环遍历字符串3");
	for(i=0; i<size; i++)
	{
		printf("%c",*(pcdata+i));
	}
	printf("\n改进后的遍历字符串的方法,用printf输出函数,控制符用百分号S\n");
	printf("%s\n",cdata);
	printf("%s\n",cdata2);
	printf("%s\n",pcdata);
	printf("\n改进后的遍历字符串的方法,用puts输出字符串函数\n");
	puts(cdata);
	putchar('\n');
	puts(cdata2);
	putchar('\n');
	puts(pcdata);
	putchar('\n');
	
	return 0;
}
/*
    补充知识:
	char cdata[] = {'h','e','l','l','o','\0'};
	    在C语言中,"\0"表示字符串的结束符或空字符。它是一个特殊的字符常量,其ASCII值为0。
	在以null-terminated string(以空字符结尾的字符串)表示的字符串中,\0用于标识字符串的
	结束位置。当程序遇到字符串中的\0时,它会认定该字符为字符串的结尾,并停止对该字符串的
	处理。这样的字符串在C语言中被视为有效的字符串表示方式。
	
	char *pcdata = "hello"; //字符串常量,不允许修改。定义一个指针指向字符串
	    这段代码 char *pcdata = "hello"; 是一种字符串字面量的赋值方式,它的实际含义是将一
	个指向字符的指针变量 pcdata 指向了一个字符数组的首地址,而这个字符数组存储了字符串常量 
	"hello" 的内容。
	    具体的实现过程是这样的,编译器会在全局数据区分配一块内存空间,并把 "hello" 这个字
	符串常量的内容存储在这个空间里。然后,编译器会将这个字符串常量所在的内存地址赋值给
	pcdata 指针变量,因此 pcdata 指针变量指向了这个字符串常量在内存中的起始地址。
        需要注意的是,在这种赋值方式下,字符串常量存储在静态区,不允许进行修改,因为这里指
	针指向的是一个常量地址。如果想修改字符串内容,需要使用 char 类型的数组或者 malloc 等函
	数分配的动态内存。而且也不建议使用 char *pcdata = "hello"; 的方式进行指针初始化,因为这
	是一个不安全的写法,容易导致内存泄漏问题。
*/

2.字符串和整型数组在存储上的区别

1.回忆如何计算数组的大小及数组元素的个数

len = sizeof(arr); //计算数组大小
len = sizeof(arr)/sizeof(arr[0]); //计算数组元素个数

2.字符串的存储方式——多了结束标志’\0’;

char cString[] = "hello"; //字符串默认会在最后一位元素后面添加一个元素'\0''\0'为字符串结束标志

3.程序代码

#include 
/*
   时间:    2023年6月30日21:55:20
   程序功能:字符串和整型数组的区别
*/

int main()
{
	int arr[] = {1,2,3,4,5};
	char cString2[] = "hello";     //字符串默认会在最后一位元素后面添加一个元素'\0'
	                               //'\0'为字符串结束标志
	char cString[5] = {'h','e','l','l','o'};//在字符数组中,不会默认添加字符结束标志
	int len;                                //'\0'
	
	puts("程序功能:字符串和整型数组的区别\n\n");
	puts("char cString2[] = “hello”;//字符串默认会在最后一位元素后面添加一个元素'杠0'");
	puts("//'杠0'为字符串结束标志");
	puts("char cString[5] = {'h','e','l','l','o'};//在字符数组中,不会默认添加字符结束标志");
	puts("//'杠0'\n\n");
	
	puts("在头文件中的几个AIP:strcpy strcmp strcat strstr中,会检测");
	puts("字符串的结束标志,所以在运用头文件时应考虑字符串结束标志");
	puts("在使用百分号s时,也会检测字符串结束标志。如果调用以上API和输出时,");
	puts("使用的是字符数组,应在最后一位元素后面添加字符串结束标志“杠0”\n\n");
	
	
	len = sizeof(arr)/sizeof(arr[0]);
	printf("整型数组的元素个数为 %d\n",len);
	
	len = sizeof(cString2)/sizeof(cString2[0]);
	printf("字符串的元素个数为 %d\n",len);
	
	len = sizeof(cString)/sizeof(cString[0]);
	printf("字符数组的元素个数为 %d\n",len);
    return 0;
}

3.sizeof 和 strlen 的区别

1.编程案例

#include 
#include  //使用strlen函数必须包含头文件
/*
   时间:2023年7月1日16:58:47
   程序功能:sizeof和strlen的区别
*/
void test()
{
	
}
int main()
{
	char cdata[] = "hello";
	char *pdata = "hello";
	void (*ptest)();             //定义一个函数指针
	ptest = test;                //函数指针指向test函数
	
	puts("程序功能:sizeof和strlen的区别");
	puts("strlen函数用于计算有效字符串的大小");
	puts("#include  //使用strlen函数必须包含头文件");
	puts("printf(“sizeof: *pdata   = %d杠n”,sizeof(*pdata));//输出结果为1,因为char *pdata = “hello”; ");
	puts("定义一个指针指向字符串首元素地址");
	puts("//*pdata代表把首元素地址中的值取出来为'h','h'为char型,所以sizeof(*pdata)为1\n\n");
	
	
	printf("sizeof: cdata    = %d\n",sizeof(cdata));
	printf("strlen: cdata    = %d\n",strlen(cdata)); //strlen函数用于计算有效字符串的大小
	printf("sizeof: pdata    = %d\n",sizeof(pdata));
	printf("strlen: pdata    = %d\n",strlen(pdata));
	printf("sizeof: *pdata   = %d\n",sizeof(*pdata));//输出结果为1,因为char *pdata = "hello"; 定义一个指
	                                                 //针指向字符串首元素地址*pdata代表把首元素地址中的值
													 //取出来为'h','h'为char型,所以sizeof(*pdata)为1
    printf("sizeof: char *   = %d\n",sizeof(char *));
	printf("sizeof: char     = %d\n",sizeof(char));
	printf("sizeof: int *    = %d\n",sizeof(int *));
	printf("sizeof: int      = %d\n",sizeof(int));
	printf("sizeof: ptest    = %d\n",sizeof(ptest));
	return 0;
}

4.动态开辟字符串

1.malloc 函数

1.函数原型

  void 芯malloc(size_t size);

2.解释

  1.c库函数void 芯malloc(size_t size)分配所需的内存空间,并返回一个指向它的指针。
  2.void 芯malloc(size_t size)
  void 芯malloc:这是一个指针函数,返回值是一个空类型的指针
  (size_t size):实参为整型数,其含义是要在堆上开辟内存空间大小

2.realloc 函数

1.函数原型

  void 芯realloc(void 芯ptr,size_t size)**

2.解释

  1.realloc扩容函数,c库函数 void 芯realloc(void 芯ptr,size_t size)尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小**
  2.void 芯realloc(void 芯ptr,size_t size)
  void 芯realloc:这是一个指针函数,返回值是一个空类型的指针
  (void 芯ptr,size_t size):
  实参void 芯ptr为一个空类型指针,填写需要扩容的指针变量。
  实参size_t size为一个整型变量,填写的是需要扩容多少字节。

3.strcpy函数

1.函数原型

  1.char 芯strcpy(char芯 dest,const char 芯src)

2.解释

  char 芯strcpy:这是一个指针函数,返回值是一个char类型的指针
  (char芯 dest,const char 芯src):实参char芯 dest:目的,const char 芯src:源
  整个函数是拷贝字符串,就会有从哪里拷贝到哪里去。所以:const char 芯src:从哪里拷贝
  const关键字用于说明被指向的字符为常量,即不能通过指针修改字符的值。
  const char 芯src声明了一个指针src,它指向常量字符。通过这个指针,可以访问和处理指向的常量字符,但不能通过该指针修改字符的值。
  char芯 dest:拷贝到哪里去。注意:它们都是指针类型,所以实参参数也为指针类型。

4.free函数

1.函数原型

  void free(void 芯ptr)

2.解释

  1.c库函数void free(void 芯ptr)释放之前调用calloc、malloc或realloc所分配的内存空间
  2.void free:空类型函数free
  (void 芯ptr):实参为空类型指针变量。
  函数作用:释放malloc函数在堆上划分的内存空间,防止出现悬挂指针。

3.作用

  1.释放内存,放在内存泄露
  2.防止悬挂指针——野指针的一种

5.memset函数

1.函数原型

  void 芯memset(void 芯str,int c,size_t n)

2.解释

  void 芯memset:这是一个指针函数,返回值是一个空类型的指针
  (void 芯str,int c,size_t n):
  实参void 芯str为一个空类型指针,填写你新开辟的内存
  实参int c为一个整型变量,填写初始化内容
  实参size_t n为一个整型变量,填写大小。
  函数功能:清理新开辟的内存空间存放的内容。

6.程序整合代码

#include 
#include  //使用malloc函数必须包含头文件
#include  //使用strcpy函数必须包含头文件
/*
   时间:    2023年7月2日14:39:27
   程序功能:动态开辟字符串
*/
void introduce()
{
	puts("程序功能:动态开辟字符串\n\n");
	puts("#include  //使用malloc函数必须包含头文件\n");
	puts("#include  //使用strcpy函数必须包含头文件\n");
	puts("p = (char *)malloc(1);  //p有了具体的内存指向,(char *)将void类型的malloc函数强制");
	puts("转换成char\n");
	puts("p = NULL; //防止指针变量p形成悬挂指针。\n");
	puts("int newlen = len - 12 + 1;         //加1的目的是为了存放字符串结束标志'杠0'\n");
	puts("printf(“扩容后地址:%x杠n”,p);      //扩容前后的地址是不变的,因为首地址不变\n");
	puts("strcpy(p,“qwertyuiopas123456789”); //虽然函数形参2为指针类型,但“qwertyuiopas”并不");
	puts("冲突,相当于char *p = “qwertyuiopas”;\n");
	puts("函数介绍:\n\n");
	puts("1.void *malloc(size_t size)");
	puts("void *malloc:这是一个指针函数,返回值是一个空类型的指针");
	puts("(size_t size):实参为整型数,其含义是要在堆上开辟内存空间大小\n");
	puts("2.char *strcpy(char* dest,const char *src);");
	puts("char *strcpy:这是一个指针函数,返回值是一个char类型的指针");
	puts("(char* dest,const char *src):实参char* dest:目的,const char *src:源");
	puts("整个函数是拷贝字符串,就会有从哪里拷贝到哪里去。所以:const char *src:从哪里拷贝");
	puts("const关键字用于说明被指向的字符为常量,即不能通过指针修改字符的值。");
	puts("const char *src声明了一个指针src,它指向常量字符。通过这个指针,可以访问和处理指");
	puts("向的常量字符,但不能通过该指针修改字符的值。");
	puts("char* dest:拷贝到哪里去。注意:它们都是指针类型,所以实参参数也为指针类型。\n");
	puts("3.void free(void *ptr);");
	puts("void free:空类型函数free");
	puts("(void *ptr):实参为空类型指针变量。");
	puts("函数作用:释放malloc函数在堆上划分的内存空间,防止出现悬挂指针。\n");
	puts("4.void *realloc(void *ptr,size_t size)");
	puts("void *realloc:这是一个指针函数,返回值是一个空类型的指针");
	puts("(void *ptr,size_t size):");
	puts("实参void *ptr为一个空类型指针,填写需要扩容的指针变量。");
	puts("实参size_t size为一个整型变量,填写的是需要扩容多少字节。\n");
	puts("5.void *memset(void *str,int c,size_t n);");
	puts("void *memset:这是一个指针函数,返回值是一个空类型的指针");
	puts("(void *str,int c,size_t n):");
	puts("实参void *str为一个空类型指针,填写你新开辟的内存");
	puts("实参int c为一个整型变量,填写初始化内容");
	puts("实参size_t n为一个整型变量,填写大小。");
	puts("函数功能:清理新开辟的内存空间存放的内容。\n\n");
	
}
int main()
{
	int i;
	char *p;
	introduce();
	p = (char *)malloc(1);  //p有了具体的内存指向,(char *)将void类型的malloc函数强制转换成char
	*p = 'c';
	free(p);
	p = NULL; //防止指针变量p形成悬挂指针。
	p = (char *)malloc(12);
	if(p == NULL)
	{
		puts("malloc error"); //在单片机中要判断
	}
	memset(p,'\0',12);
	printf("扩容前地址:%x\n",p);
	int len = strlen("qwertyuiopas123456789");
	int newlen = len - 12 + 1;         //加1的目的是为了存放字符串结束标志'\0'
	realloc(p,newlen);
	printf("扩容后地址:%x\n",p);      //扩容前后的地址是不变的,因为首地址不变
	strcpy(p,"qwertyuiopas123456789"); //虽然函数形参2为指针类型,但"qwertyuiopas"并不冲突,相当于
	                                   //char *p = "qwertyuiopas";
	puts(p);
    puts("end");
	
}
/*
    函数介绍:
	1.void *malloc(size_t size)
	void *malloc:这是一个指针函数,返回值是一个空类型的指针
	(size_t size):实参为整型数,其含义是要在堆上开辟内存空间大小
	2.char *strcpy(char* dest,const char *src);
	char *strcpy:这是一个指针函数,返回值是一个char类型的指针
	(char* dest,const char *src):实参char* dest:目的,const char *src:源
	整个函数是拷贝字符串,就会有从哪里拷贝到哪里去。所以:const char *src:从哪里拷贝
	const关键字用于说明被指向的字符为常量,即不能通过指针修改字符的值。
	const char *src声明了一个指针src,它指向常量字符。通过这个指针,可以访问和处理指
	向的常量字符,但不能通过该指针修改字符的值。
	char* dest:拷贝到哪里去。注意:它们都是指针类型,所以实参参数也为指针类型。
	3.void free(void *ptr);
	void free:空类型函数free
	(void *ptr):实参为空类型指针变量。
	函数作用:释放malloc函数在堆上划分的内存空间,防止出现悬挂指针。
	4.void *realloc(void *ptr,size_t size)
	void *realloc:这是一个指针函数,返回值是一个空类型的指针
	(void *ptr,size_t size):
	实参void *ptr为一个空类型指针,填写需要扩容的指针变量。
	实参size_t size为一个整型变量,填写的是需要扩容多少字节。
	5.void *memset(void *str,int c,size_t n);
	void *memset:这是一个指针函数,返回值是一个空类型的指针
	(void *str,int c,size_t n):
	实参void *str为一个空类型指针,填写你新开辟的内存
	实参int c为一个整型变量,填写初始化内容
	实参size_t n为一个整型变量,填写大小。
	函数功能:清理新开辟的内存空间存放的内容。
	
*/

5.字符串几种常用的API

1.输出字符串

puts(); //输出字符串
printf("%s",p); //%s为输出字符串控制符

2.获取字符串

1.gets函数

  1函数原型
  char 芯gets(char 芯str);

  2.解释:
  因为本函数可以无限读取,易发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值

2.scanf(“%s”,p);

3.输入输出字符串程序

#include 
/*
   时间:    2023年7月3日16:22:37
   程序功能:输入输出字符串
*/
int main()
{
	char str[] = "asdfghjkl";
	char *p = "qwertyuiop";
    char str2[128] = {'\0'};
	puts(str);
	puts(p);
	printf("%s\n",str);
	printf("%s\n",p);
	puts("请输入字符串");
	scanf("%s",str2);
	puts(str2);
	
	
	return 0;
}

4.自己实现字符串拷贝函数

1.预备知识一:指针函数

  char *myStrcpy(char *dest,char *src)
  char *myStrncpy(char *dest,char *src,int count)

2.预备知识二:指针偏移*dest++ = *src++;
3.注:预备知识不知道的同学,可以看我写的指针博文——点击
4.程序代码
#include 
/*
   时间:    2023年7月3日22:03:43
   程序功能:自己实现字符串拷贝函数
*/
char *myStrcpy(char *dest,char *src)
{
	if(dest==NULL || src==NULL)//判断函数所有实参是否为空,为空就退出函数并返回空。
	{
		return NULL;
	}
	char *bak = dest;
	while(*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = '\0';
	return bak;
}
char *myStrcpy2(char *dest,char *src)
{
	if(dest==NULL || src==NULL)
	{
		return NULL;
	}
	char *bak = dest;
	while(*src != '\0')
	{
		*dest++ = *src++;
	}
	*dest = '\0';
	return bak;
}
char *myStrcpy3(char *dest,char *src)
{
	if(dest==NULL || src==NULL)
	{
		return NULL;
	}
	char *bak = dest;
	while((*dest++ = *src++)!= '\0');
	*dest = '\0';
	return bak;
}
char *myStrncpy(char *dest,char *src,int count)
{
	if(dest==NULL || src==NULL || count==0)
	{
		return NULL;
	}
	char *bak = dest;
	while(*src != '\0' && count>0)
	{
		*dest++ = *src++;
		count--;
	}
	if(count>0)//将想输出字符串的长度大于已有字符串长度后面的字符串地址赋字符串结束标志
	           //'\0'
    {
   		while(count>0)
		{
			count--;
			*dest++ == '\0';
		}
		return dest;
	}
	*dest = '\0'; //在 myStrncpy 函数中,如果没有对最后一个地址赋字符串结束标志'\0',打印会
	              //出错。出现中文字“数”。
	return bak;
}
void introduce()
{
	puts("程序功能:自己实现字符串拷贝函数\n\n");
	puts("程序主要知识点:");
	puts("1.指针函数:");
	puts("char *myStrcpy(char *dest,char *src)");
	puts("char *myStrncpy(char *dest,char *src,int count)");
	puts("2.指针偏移:");
	puts("*dest++ = *src++;\n\n");
}
int main()
{
	int len;
	char str[128] = {'\0'};
	char p[128];
	introduce();
	puts("请输入你想输出的字符串");
	scanf("%s",p);
	puts("请输入你要输出的字符串长度。");
	scanf("%d",&len);
	myStrncpy(str,p,len);
	puts(str);
	return 0;
}

5.C语言断言函数assert

1.原理和if…else一样
2.定义1

  assert 的作用是现计算表达式 expression ,如果其值为假(为0),那么它先 stder 打一条出错信息,然后通过调用 abort 来终止程序运行。
  使用assert 的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。

3.定义2

  在C语言中,断言是一种用于检查程序运行时条件的函数。它通常用于验证某个表达式是否为真,如果表达式为假,则会触发断言失败的操作,例如输出错误信息并终止程序的执行。
  C语言中使用断言的函数是assert(),它定义在assert.h头文件中。assert()函数的原型为:
  void assert(int expression);
  参数expression是一个表达式,如果它的值为真(即非零),则程序继续执行;如果它的值为假(即0),则会触发断言失败,导致程序终止。

4.程序终止现象为

Assertion failed!

Program: D:\\C\ \API\Cassert\a.exe
File: Assert_function.c, Line 10

Expression: *str != '\0'
5.程序代码
#include 
#include   //使用assert函数必须包含头文件
#include   //使用malloc函数必须包含头文件
/*
   时间:2023年7月4日00:18:38
   程序功能:C语言断言函数assert
*/
char *myInput(char *str)
{
	assert(*str != '\0' );
	char *bak = str;
	puts("请输入你需要输出的字符串");
	scanf("%s",str);
	return bak;
}
void introduce()
{
	puts("程序功能:C语言断言函数assert\n\n");
	puts("assert函数介绍");
	puts("\t定义1:");
	puts("\tassert 的作用是现计算表达式 expression ,如果其值为假(为0),那么它先 stder 打一条出错");
	puts("信息,然后通过调用 abort 来终止程序运行。");
	puts("\t使用assert 的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。");
	puts("\t定义2:");
	puts("\t在C语言中,断言是一种用于检查程序运行时条件的函数。它通常用于验证某个表达式是否为真,");
	puts("如果表达式为假,则会触发断言失败的操作,例如输出错误信息并终止程序的执行。");
	puts("\tC语言中使用断言的函数是assert(),它定义在assert.h头文件中。assert()函数的原型为:");
	puts("\tvoid assert(int expression);");
	puts("\t参数expression是一个表达式,如果它的值为真(即非零),则程序继续执行;如果它的值");
	puts("为假(即0),则会触发断言失败,导致程序终止。");
	puts("\t程序终止现象为:");
	puts("\t Assertion failed!\n\n");
	puts("\t Program: D:杠杠C杠 杠API杠Cassert杠a.exe\n");
	puts("\t File: Assert_function.c, Line 10\n\n");
	puts("\t Expression: *str != '杠0'\n\n");
}
int main()
{
	char *p = "\0";  //这里有改动
	int len;
	introduce();
	puts("请输入你需要输出的字符串长度");
	scanf("%d",&len);
	p = (char *)malloc(len);
	myInput(p);
	puts(p);
	free(p);
	return 0;
}

6.字符串拼接函数strcat

1.定义

  1.函数原型:char 芯strcat(char 芯dest,const char 芯src);
  2.解释:把src所指向的字符串(包括"\0")复制到dest所指向的字符串后(删除芯dest原来末尾的"\0")。要保证芯dest足够长,以容纳被复制进来的芯src。芯src中原有的字符不变,返回指向dest的指针

2.使用strcat函数程序代码
#include 
#include  //使用strcat函数必须包含头文件
/*
   时间:  2023年7月5日17:59:50
   程序功能:strcat函数使用
*/
void introduce()
{
	puts("程序功能:strcat函数使用\n\n");
	puts("函数原型:char *strcat(char *dest,const char *src);\n");
	puts("解释:把src所指向的字符串(包括“杠0”)复制到dest所指向的字符串后面");
	puts("删除*dest原来末尾的“杠0”)。要保证*dest足够长,以容纳被复制进来");
	puts("的*src。*src中原有的字符不变,返回指向dest的指针\n\n");

}
int main()
{
	char str[128] = "my dream";
	char *p = " car";
	char *p2;
	introduce();
	p2 =strcat(str,p);  //strcat函数用于拼接字符串
	puts(p2);
	return 0;
}
3.实现strcat函数程序代码
#include 
#include 
#include  //使用strlen,strcpy函数必须包含头文件
/*
   时间:    2023年7月5日21:32:29
   程序功能:实现strcat函数
*/
char *myStrcat(char *desk,char *src)
{
	char *bak = desk;
	assert(desk!=NULL && src!=NULL);
	while(*desk != '\0')
	{
		*desk++;
	}
	while((*desk++ = *src++) != '\0');
	*desk = '\0';
	return bak;
}
char *myStrcat2(char *desk,char *src)
{
	char *bak = desk;
	assert(desk!=NULL && src!=NULL);
	while(*desk)//*desk = '\0'while循环条件语句中是不成立的。
	{
		*desk++;
	}
	while((*desk++ = *src++) != '\0');
	*desk = '\0';
	return bak;
}
char *myStrcat3(char *desk,char *src)
{
	char *bak = desk;
	assert(desk!=NULL && src!=NULL);
	strcpy(desk+strlen(desk),src);
	return bak;
}
char *myStrcat4(char *desk,char *src)
{
	char *bak = desk;
	assert(desk!=NULL && src!=NULL);
	for(; *desk!='\0';desk++);
	for(; (*desk++ = *src++)!= '\0';);
	*desk = '\0';
	return bak;
}
int main()
{
	char str[128] = "my dream";
	char *p = " car is BYD";
	
	puts("程序功能:实现strcat函数\n\n");
	
	myStrcat(str,p);
	puts(str);
	myStrcat2(str,p);
	puts(str);
	myStrcat3(str,p);
	puts(str);
	myStrcat4(str,p);
	puts(str);
	return 0;
}

7.字符串比较函数strcmp

1.定义

  1.函数原型:int strcmp(const char 芯s1,const char 芯s2);
  2.理解:若str1=str2,则返回零;若str1str2,则返回正数

2.使用strcmp函数代码
#include 
#include 
/*
   时间:    2023年7月6日17:52:47
   程序功能:使用字符串比较函数strcmp
*/
void introduce()
{
	puts("程序功能:使用字符串比较函数strcmp\n\n");
	puts("char c1[6];  //注意初始化时得留一个元素位置来用于字符串结束标志“杠0”存放\n");
	puts("函数原型为:");
	puts("int strcmp(const char *s1,const char *s2);");
	puts("含义为:");
	puts("若str1=str2,则返回0;若str1str2,则返回正1\n\n");
}
int main()
{
	char c1[6];  //注意初始化时得留一个元素位置来用于字符串结束标志“杠0”存放
	char c2[6];
	char yesOrNoC;
	int ret;
	introduce();
	do
    {	
		puts("请输入第一个字符串【5个字符以内】");
	    scanf("%s",&c1);
	    puts("请输入第二个字符串【5个字符以内】");
	    scanf("%s",&c2);
		ret = strcmp(c1,c2);
		if(ret == 0)
		{
			puts("两个字符一样");
		}
		else if(ret == -1)
		{
			puts("第一个字符串的ASCII码小于第二个字符串的ASCII码");
		}
		else
		{
			puts("第一个字符串的ASCII码大于第二个字符串的ASCII码");
		}
		printf("ret = %d\n",ret);
		puts("是否继续判断 y/n");\
		getchar();
		scanf("%c",&yesOrNoC);
	}while(yesOrNoC=='Y' || yesOrNoC=='y');
	
	
	return 0;
}
3.实现strcmp函数代码
#include 
/*
   时间:  2023年7月6日21:26:49
   程序功能:字符串比较函数strcmp函数实现
*/
void introduce()
{
	puts("程序功能:字符串比较函数strcmp函数实现\n\n");
	puts("重点知识提要:\n");
	puts("char *bakstr1 = str1;  //把指针变量bakstr1指向字符串str1的首地址");
	puts("char *bakstr2 = str2;  //把指针变量bakstr2指向字符串str2的首地址\n");
	puts("while(*str1 && *str2 && (*str1==*str2))");
	puts("{");
	puts("	str1++;");
	puts("	str2++;");
	puts("}//指针变量str1和str2偏移后,指针变量内部值就会为‘杠0’,就不成立if,");
	puts("while的条件判断\n");
	puts("str1 = bakstr1;  //把指针回归\n");
	puts("n_str1 += *str1; //==>n_str1 = n_str1+*str1\n\n");
}
int myStrcmp(char *str1,char *str2)
{
	int ret = 0;
	int n_str1;
	int n_str2;
	char *bakstr1 = str1;  //把指针变量bakstr1指向字符串str1的首地址
	char *bakstr2 = str2;  //把指针变量bakstr2指向字符串str2的首地址
	while(*str1 && *str2 && (*str1==*str2))
	{
		str1++;
		str2++;
	}//指针变量str1和str2偏移后,指针变量内部值就会为'\0',就不成立if,while的条件判断
	if(*str1 || *str2)
	{
		str1 = bakstr1;  //把指针回归
		str2 = bakstr2;
		while(*str1)
		{
			n_str1 += *str1; //==>n_str1 = n_str1+*str1
			str1++;
		}
		*str1 = '\0'; //把字符串末尾赋结束标志
		while(*str2)
		{
			n_str2 += *str2; //==>n_str2 = n_str2+*str2
			str2++;
		}
		*str2 = '\0'; //把字符串末尾赋结束标志
		ret = n_str1 - n_str2;
	}
	if(ret<0)
	{
		ret = -1;
	}else if(ret>0)
	{
		ret = 1;
	}else
	{
		ret = 0;
	}
	return ret;
}
int main()
{
	char str1[7];
	char str2[7];
	char yesOrNoC;
	int ret;
	introduce();
	do
	{
		puts("请输入第一个字符串【0~6个字符内输入】");
		scanf("%s",&str1);
		puts("请输入第二个字符串【0~6个字符内输入】");
		scanf("%s",&str2);
		ret = myStrcmp(str1,str2);
		if(ret == 0)
		{
			puts("你输入的两个字符的ASCII码相等");
		}else if(ret == 1)
		{
			puts("你输入的第一个字符的ASCII码大于第二个字符的ASCII码");
		}else
		{
			puts("你输入的第一个字符的ASCII码小于第二个字符的ASCII码");
		}
		printf("ret = %d\n",ret);
		getchar();
		puts("你需要继续判断吗 y/n");
		scanf("%c",&yesOrNoC);
		getchar();
	}while(yesOrNoC=='y' || yesOrNoC=='Y');
	
	return 0;
}

6.结束语

  您能在百忙之中抽出时间看到这里,我很感谢,也很高兴。字符串的难点在于指针章节中的指针函数,只要指针章节学得懂,其实是很简单的。

你可能感兴趣的:(学习嵌入式笔记,学习,c语言,单片机,stm32,51单片机)