Record11—字符串基本操作

目录

字符串的基本操作

推演字符数组

怎样用字符串来初始化字符数组

用数组下标或指针来操作字符串

"[]"操作和"*p"操作之间的关系

总体代码


1级指针的典型用法主要有两个表现,一个是1级指针数组,一个是1级指针字符串。

其中,1级指针数组部分,在之前的博客已有记录,故本篇博客专记1级指针字符串的用法

字符串的基本操作

1)C语言里面的字符串都是以0结尾的字符串

2)在C语言中是没有字符串类型,是通过字符数组来模拟字符串的。所以说,在C语言中掌握字符串就是掌握字符数组。

3)字符串的内存分配,可以在堆区上也可以在栈区上,也可以在全局区。

推演字符数组

//字符数组 初始化
void main51()
{

	//1 指定长度  
	char buf2[100] = {'a', 'b', 'c', 'd'};  
	//1-1char buf3[2] = {'a', 'b', 'c', 'd'}; //如果初始化的个数大于内存的个数 编译错误
	//1-22//后面的buf2[4]-buf2[99] 0


	//2 不指定长度  C编译器会自动帮程序员 求元素的个数
	char buf1[] = {'a', 'b', 'c', 'd'};  //buf1是一个数组 不是一个以0结尾的字符串

	printf("buf2: %s \n", buf2);

	printf("buf2[88]:%d \n", buf2[88]);

	printf("hello....\n");
	system("pause");

	return ;
}

上面展示了定义一个字符数组的方法,其中buf2是指定了数组长度,buf1是不指定数组长度的。 不指定数组长度的比指定的好,如果不指定数组长度,那每填入一个元素,编译器会自动的扩展长度,如果指定了数组长度,一旦填入的元素长度超过了指定的,就会报错。运行如下:

 打印出来buf2[88]里面的元素是0。说明创建的数组中的未赋值位,都是靠0来填充的。

需要指明的是,在创建的buf1,这个不指定数组长度的字符数组,填入了四个元素,它的数组长度是4,而不是5,因为,这种创建方法,并不是C风格的创建方式,所以,它的末尾不是0。这也是字符串和字符数组的区别(区别就是末尾可能出现不为0的情况)。

怎样用字符串来初始化字符数组

如下这个程序推演,

//用字符串 来 初始化字符数组
//strlen() 长度 不包括0
//sizeof() 内存块的大小
void main52()
{
	int size = 0;
	char buf3[] = "abcd"; // buf3 作为字符数组 应该是5个字节 //作为字符串 应该4个字节

	int len = strlen(buf3);
	printf("buf3字符的长度:%d \n", len); //4

	//buf3 作为数组 数组是一种数据类型 本质(固定小大内存块的别名)
	size = sizeof(buf3); //
	printf("buf3数组所占内存空间大小:%d \n", size); //5

	printf("hello....\n");
	system("pause");
	return ;
}

需要看的是,所创建的buf3和之前所创建的buf2的区别。这里的buf3是直接存入了“abcd” ,那么对应的字符串长度为4,对应的字符数组长度为5,多开的那个是“\0”;而buf2的长度为4,因为它是一个一个元素赋值的,每个元素都加上了单引号。注意区分。

同样一个buf3,如果是求其作为字符串长度,就用"strlen()"函数来求;如果是求这个作为字符数组的长度,就用"sizeof()"函数(数组是一种数据类型,数据类型本质上是固定大小的内存块别名,求数据类型的长度,统一都要用"sizeof()")

运行如下:

 另外,可以再做一个实验,建立一个buf4:


	{
		char buf4[128] = "abcd"; // buf
		printf("buf4[100]:%d \n", buf4[100]);
	}

 运行结果,

 证明在buf4中,未放值的位置,数值全都是0。

用数组下标或指针来操作字符串

比如说,定义一个数组,打算用数组下标的方式来操作内存。创建一个buf5,buf5这个变量代表的是buf5所创建的这个数组的首元素地址。 如下演示两种访问数组内容的方式:

//通过数组下标 和 指针
void main58()
{
	int		i = 0;
	char	*p = NULL;
	char buf5[128] = "abcdefg"; // buf

	for (i=0; i<strlen(buf5); i++)
	{
		printf("%c ", buf5[i]); 
	}
	
	p = buf5; //buf 代表数组首元素的地址

	for (i=0; i<strlen(buf5); i++)
	{
		p = p +i;
		printf("%c ", *p ) ;
	}

	printf("hello....\n");
	system("pause");
}

 运行如下:

 

"[]"操作和"*p"操作之间的关系

先看看中括号“[]”的本质是什么?还按上面的程序里面接着写,发现下面这种写法,依然可以达到访问字符串数据的功能。

	//buf
	for (i=0; i<strlen(buf5); i++)
	{
		printf("%c ", *(buf5+i) ) ;
	}

横向比较一下,以上所用的三种方式:"buf5[i]"、"*(p+i)"、"*(buf5+i)" 是等价的,第一种方式是按人类最容易接受的方式来表达,第二种方式是按照编译器最能够接受的方式来表达,那第三种呢?接着看。

怎样完成中括号和指针的互换?推导过程如下,

[] *的推导过程
buf5[i] ===> buf5[0+i]; ==> *(buf5+i);

"[]"操作和"*p"操作没有多大区别,本质是一样的,只不过前者更方便我们阅读,其实,我们"*(buf5+i)" 这样表达,相当于是替编译器做了这个转换工作而已。最终,即使不这样,编译器也会把最终内容翻译成,"*(buf5+i)" 这个样式的。

 但是,buf5和p之间,还是有些区别的,buf5是一个指针变量,那是否可以给buf5赋值呢?

{
   buf5 = buf5 + 1;
   buf5 = 0x11;
}

 那么就试试,给buf5加1,结果编译结果报错,那这是为什么呢?这是因为,在buf5这个指针变量创建的开始,就被C编译器定义成只读的常量,即只能被读,不可被修改。buf5变成了一个常量指针,那这么做又是为什么呢?很简单,这是因为站在内存四区的角度看,定义一个buf5是在栈区定义的,到时候main运行完,析构的时候,编译器也肯定是根据buf5所指向的地址开始析构,如果,让用户很容易的就修改了buf5的值,那当main运行结束的时候,编译器依据被修改后的buf5首地址值去析构内存,很容易造成漏掉某些内存没有被析构掉。这就给系统释放内存留有很大的隐患,所以,要把它做成常量指针。如果非想改变指针的指向,那就只有用“*p”的方式来间接改变指针的指向(见上方式2来改变数组内容),但不能直接改buf5这个变量。

总体代码

dm05_字符串基本操作.c

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

//一级指针的典型用法
//数组 int a[10]
//字符串 
//1 C语言的字符串 以零结尾的字符串
//2 在C语言中没有字符串类型  通过字符数组 来模拟字符串 
//3 字符串的内存分配  堆上 栈上 全局区 (很重要)


//字符数组 初始化
void main51()
{

	//1 指定长度  
	char buf2[100] = {'a', 'b', 'c', 'd'};  
	//1-1char buf3[2] = {'a', 'b', 'c', 'd'}; //如果初始化的个数大于内存的个数 编译错误
	//1-22//后面的buf2[4]-buf2[99] 0


	//2 不指定长度  C编译器会自动帮程序员 求元素的个数
	char buf1[] = {'a', 'b', 'c', 'd'};  //buf1是一个数组 不是一个以0结尾的字符串

	printf("buf2: %s \n", buf2);

	printf("buf2[88]:%d \n", buf2[88]);

	printf("hello....\n");
	system("pause");

	return ;
}

//用字符串 来 初始化字符数组
//strlen() 长度 不包括0
//sizeof() 内存块的大小
void main52()
{
	int size = 0;
	char buf3[] = "abcd"; // buf3 作为字符数组 应该是5个字节 //作为字符串 应该4个字节

	int len = strlen(buf3);
	printf("buf3字符的长度:%d \n", len); //4

	//buf3 作为数组 数组是一种数据类型 本质(固定小大内存块的别名)
	size = sizeof(buf3); //
	printf("buf3数组所占内存空间大小:%d \n", size); //5

	printf("hello....\n");

	{
		char buf4[128] = "abcd"; // buf
		printf("buf4[100]:%d \n", buf4[100]);
	}
	system("pause");
	return ;
}

//通过数组下标 和 指针
void main58()
{
	int		i = 0;
	char	*p = NULL;
	char buf5[128] = "abcdefg"; // buf

	for (i=0; i<strlen(buf5); i++)
	{
		printf("%c ", buf5[i]); 
	}
	
	p = buf5; //buf 代表数组首元素的地址

	for (i=0; i<strlen(buf5); i++)
	{
		p = p +i;
		printf("%c ", *p ) ;
	}

	//buf
	for (i=0; i<strlen(buf5); i++)
	{
		printf("%c ", *(buf5+i) ) ;
	}

	//[] *的推导过程
	// buf5[i] ===> buf5[0+i]; ==> *(buf5+i);

	{
		//buf5 = buf5 + 1;
		//buf5 = 0x11;
	}
	printf("hello....\n");
	system("pause");
}

// []的本质 :和*p 是一样 ,只不过是符合程序员的阅读习惯
// buf5 是一个指针,  只读的常量  buf5是一个常量指针  析构内存的时候,保证buf所指向的内存空间安全释放
//为什么这么做?

//p普通指针和内存首地址区别



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值