C语言n番战--字符串(六)

这篇博客详细介绍了C语言中的字符串,包括字符串的基本概念、定义方式、结束符''、sizeof与strlen的区别、动态开辟字符串(malloc、calloc、realloc和free)以及常用的字符串API,如gets、puts、fgets、fputs等。文章还探讨了字符串API的使用注意事项和内存管理问题。
摘要由CSDN通过智能技术生成

嵌入式之路,贵在日常点滴

                                                                ---阿杰在线送代码

目录

一、字符串的基本概念

二、字符串的定义方式与输出

二、字符串的结尾是 ’ \0 ’

三、sizeof和strlen的区别 

四、 动态开辟字符串

malloc函数 

free函数 

calloc函数  用得少

realloc函数

malloc、calloc、realloc小结

memset函数

五、字符串常用的API(API:预先定义的函数)

gets() 

puts()

非法内存问题 

fgets()

fputs() 

strcpy、strncpy —— 拷贝 

函数名:assert()

strcat —— 拼接

strcmp —— 比较 

strncmp

strchr、strstr —— 检索 

strlwr、strupr —— 大小写转换 

strtok —— 分割 

一、字符串的基本概念

  • 在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。
  • 空字符(Null character又称结束符,缩写 NUL,是一个数值为 0 的控制字符,\0 是转义字符,意思是告诉编译器,这不是字符 0,而是空字符。
  • 字符串是位于双引号中的字符序列
  • 在内存中以“\0”结束,所占字节比实际多一个

  • 在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串
    • 当把一个字符串存入一个数组时,会把结束符‘\0’存入数组,,并以此作为该字符串是否结束的标志。

二、字符串的定义方式与输出

#include "stdio.h"

int main()
{
	//int i;
	//定义方式一
	char cdata[] = {'h','e','l','l','o'};//字符数组
	//定义方式二
	char cdata2[] = "hello";//字符串 后面默认自加/0 字符串变量:允许被修改
	//定义方式三
	char *pchar = "hello";//字符串 后面默认自加/0   字符串常量:不允许被修改					
	
	//输出方式一:遍历的方式输出字符串
	for(int i=0;i<5;i++)
	{
		//printf("%c",cdata[i]);
		//printf("%c",cdata2[i]);
		printf("%c",*(pchar+i));
	}
	
	// 输出方式二:%s:字符串型格式符输出
	printf("%s\n",cdata);
	printf("%s\n",cdata2);
	printf("%s\n",pchar);
	
	//输出方式三:调用字符串API
	puts(pchar);
	
	return 0;
}

运行结果:

hellohello
hello
hello
hello 

注意:

1、

定义方式一是一个数组,不是字符串
C语言中确定一个字符串结束标记为'\0',一个大小为N的字符数组,最多能存1个长度为N-1的字符串,加上一个结束标记就是N个了,
如果没有结束标记,那就不能当字符串来处理,而只能当数组来处理 

2、

定义方式二是字符串变量,其字符允许被修改

定义方式三是字符串常量,其字符允不许被修改

    //检测字符串变量和字符串常量
    cdata2[1] = 'a';//正常执行
    *pchar = 'm';//强行改变会出现段错误,后文无法正常执行

3、

//省略元素个数时, 不能省略末尾的\0

// 不正确地写法,结尾没有\0 ,只是普通的字符数组

char name4[] = {'l','n','j'};

4、

//"中间不能包含\0", 因为\0是字符串的结束标志
//\0的作用:字符串结束的标志
    char name[] = "c\0ool";
    printf("name = %s\n",name);
输出结果: c

5、

其中第二种定义方式 char cdata2[] = "hello"; 不指明数组的大小,只给出了数组名,而数组名的值是个指针常量,也就是数组第一个元素的地址。

是不是可以猜想,首地址就是字符串的关键呢?

指针也指明了地址,故可以用指针的方式定义字符串,即字符串指针。也是定义字符串的常用方式。

char *pchar = "hello";//字符串 后面默认自加/0   字符串常量:不允许被修改

注意: 这里说的定义是同时赋值,而不是等待赋值。之所以不需要给指针pchar分配空间,是因为进行了初始化,编译的时候系统就知道需要分配多大的空间,否则要开辟空间。(后文中也有涉及)。 

char *p;//野指针,没有明确的内存指向,危险

在这里需要开辟空间 后文会讲如何开辟

*p = 'a';//导致段错误

二、字符串的结尾是 ’ \0 ’

#include "stdio.h"

int main()
{
	//字符数组和字符串的区别:
    char cdata[] = {'h','e','l','l','o'};//字符数组
	char cdata2[] = "hello";//字符串的结束标志'\0'
	int len;
	
	len = sizeof(cdata)/sizeof(cdata[0]);	
	printf("len = %d\n",len);
	
	//请计算数组cdata的元素个数
	//len = sizeof(cdata)/sizeof(char);
	len = sizeof(cdata2)/sizeof(cdata2[0]);	
	printf("len = %d\n",len);
	
	return 0;
}

运行结果:

len = 5
len = 6

使用字符数组然后以%s输出,可能性上会出现问题, 那么如果非要用字符数组来表示字符串并以%s输出呢。

char cdata[6] ={'h','e','l','l','o','\0'};//字符串的结束标志\0

printf("%s",cdata); 

三、sizeof和strlen的区别 

#include "stdio.h"
#include "string.h"

void test()
{
	
}

int main()
{
	char cdata[128] = "hello";//字符串的结束标志'\0'
	printf("sizeof:%d\n",sizeof(cdata));//算的是数组的大小
	printf("strlen:%d\n",strlen(cdata));//算的是字符串的大小
	
	char *p = "hello";
	void (*ptest)();
	ptest = test;
	
	//p是一个char *,sizeof来计算的时候,得出是计算机用多少字节来表示一个地址 
                                        即指针变量所占用的内存大小
	printf("sizeof:p      :%d\n",sizeof(p));
	printf("sizeof:char*  :%d\n",sizeof(char*));
	printf("sizeof:int*   :%d\n",sizeof(int*));
	printf("sizeof:ptest  :%d\n",sizeof(ptest));
	printf("sizeof:char   :%d\n",sizeof(char));
	printf("strlen        :%d\n",strlen(p));//算的是字符串的大小
	
	return 0;
}

运行结果

sizeof:128
strlen:5

指针变量所占用的内存大小仅仅取决指针本身的大小,不取决于指针指向的数据类型大小
sizeof:p      :8
sizeof:char*  :8
sizeof:int*   :8
sizeof:ptest  :8
sizeof:char   :1
strlen        :5 

实际上hello长这样: 

hello\0\0\0\0\0\0..........

strlen当遇到\0时便停止计算,是专门用来计算字符串的长度。 

strlen使用注意字符数组当做字符串来用?

有一个说法是:把字符数组当做字符串来使用时,最后一个元素要是'\0',否则strlen()计算时就会发生“停不下来”,直到遇到内存的'\0',故计算出来就不会是一个准确的值。例如:

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

int main()
{
        char array[5] = {'a','b','c','d','e'};
        printf("%d\n",strlen(array));

        return 0 ;
}

放在树莓派上运行,结果都是5。而在啊哈C中,都是6。 

四、 动态开辟字符串

在C中我们开辟内存空间有两种方式 :

1.静态开辟内存

例如:

int a;
int b[10];

这种开辟内存空间的特点是

所开辟的内存是在栈中开辟固定大小的 ,如a是4字节 ,数组b是40字节 ,并且数组在申明时必须指定其长度 , 如果是全局数组的话,内存是在编译时分配好的,如果是局部变量数组的话,运行时在栈上静态分配内存。不管是全局数组还是局部数组,它们都有一个特点,那就是数组大小是确定的,是代码中写死的。那如果我们想在程序运行时才确定一个数组的大小 , 前两种在栈上分配内存的方法显然是不行的 , 举个例子 :
 

int n;
scanf("%d", &n);
int a[n];

这样编写会在编译时出错 , 编译器会提醒[ ]中应为常量表达式 , 在C中定义数组时可以用的有以下几种 ,例:

#define N 10
enum NUM{
	M=10
};
int a1[N];
int a2[10];
int a3[M];

需要注意的是 ,C中const int n =10 ; n并不能作为数组长度定义数组 , 但C++中则可以 , 
但我们对于开辟空间的需求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值