%s、%c、字符常量、字符串常量,const char*,指针数组,字符串数组总结

首先明确以下几点:

1.字符串是一个数组,C语言中没有字符串类型的,字符串是由字符元素组成的数组。

2.%s用于输出字符串类型的内容,%c输出单个字符。

3.一般讲到常量指针const char*,基本都是针对字符串的。比如const char* p=“abc"。(“abc”实际上是一个地址,所以应该赋值给一个指针变量。)当然,对字符常量,const chat* p=‘a’也可以,但是改语句的作用是把字符常量a的ASCII码赋值给指针变量p,这在实际应用中没有什么意义。

4.因为前几天一直纠缠于字符常量和字符串常量中,所以错误的理解成了const char* p='a',也是将字符常量a的地址给到指针变量p了。但要注意,单个的字符常量不是数组,只有涉及到数组时,才有指针变量时字符串常量首字符的存储地址这一说法,单个字符串不是数组,根本就没有什么‘a’表示字符常量a的存储地址这种说法!这和第二条也是相对应的。

就记住:const char*基本是和字符串,注意是字符串,是一个数组相对应的!

5.const char*是针对字符串来说的,const char* 变量名[ ],是指针数组,是一个“二级指针”,里面存储的是指针变量的地址,所以是二级指针。

6.字符串是一个字符数组,即使是"A",也是一个字符串,也应该用char s[ ]="A",而不是char s="A"。

7.只有对于数组,才有数组名为第一个元素所在地址,而且数组名是一个指针常量。也就是对于字符串,才有数组名是一个指针,对于单个的字符,不是数组,没有说字符变量名是一个地址的说法。

8.看一下,犯过错误。c语言中不能将字符串赋值给字符数组https://blog.csdn.net/tjh1998/article/details/114628498?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link

下面看程序实例,关于更好的理解printf 输出字符、字符串,以及const char* 和字符串数组:

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

#define MAX 3

int main(int argc, char* agrv[])
{

	const char* a = 'a';
	//a是一个字符常量,不是数组,这个语句的意思是把指针a赋值为字符'a'的ASCII码。


	//const	char* q = { "abc", "123" };
	//这样写是不对的,这是字符串数组,应该是char* q[],这实际上是一个数组的数组,因为字符串本身就是数组。注意,数组元素就是要写成[]。

	char* e = 'd';//此语句的含义也是把字符d的ASCII作为地址赋值给指针变量n

	//这样表达是不对的,因为'd'是单个字符,不是一个数组,没有说首个元素的地址什么的,这样写本身就是错误的。(本人比较喜欢重复说,哈哈)

	//字符串是一个数组

	printf("************************************\n");

	printf("%d\n", e);//输出的是字符d的ASCII码100,因为e的值是'd'

	// printf("%c\n", *e);//这个语句是不能执行的,这个语句的意思是给一个指针变量复制了字符
	//常量'd'的ASCII地址,地址为字符d的ASCII码100的内存是不一定能被访问的。
	/*
	同样也就解释了之前的疑问,为什么const char*是针对字符串,而不是字符来说的呢,
	因为单个字符是一个数组,没有说'a',就表示a这个常量字符的说法。而字符串是数组,有地址传递的这个概念。	当然,字符常量也是存储在系统管理的常量存储区中的。*/

	// //=====================下面的程序是对于%s和%c的使用================================	 
	printf("***************************\n");
	// 	
	char* k = "abc";//(实际上就是const char* k="abc";)


	printf("pointer k is %p\n", k);//输出字符串abc的首地址


	//	printf("%s\n", *k);
	/*不能执行,因为k只是存储了字符串的首地址,*k实际上只是首字符a,单个字符不能用%s输出。*/

	printf("%c\n", *k);//可以执行,输出首字母a

	printf("%s\n", k);

	/*输出字符串abc。这是产生了一个疑问,为什么k前面不用加取值符号*就可以输出字符串常量abc呢。如果是*k,指的其实是首字符a,如果再搭配%s,肯定是有错误的。而且printf输出%s形式的数据时,后面跟的量应该是字符串指针或者字符串数组名。对于字符数组,采用遍历循环的方式才能把每个字符依次输出。*/


	printf("**********************\n");


	//实际上,字符串数组名是一个二级指针,是指针的指针!
	const char* n[] = {"abcdef", "BC" };
	//%s后面要跟一个指向字符串常量的一级指针
	printf("%s\n", n[0]);//认为输出a,结果是abcdef,因为n[0]是字符串常量abcdef的首地址。
	printf("%s\n", n);//乱码,这个n实际上是一个地址的地址,是一个二级指针,不是n[0]
	printf("%s\n", *n);//输出abcdef,相当于n[0],这也就是*数组名=数组第一个元素的值。
	/*
	n[0]就明确表明了是n[]数组的第一个元素,与数组名n是不一样的,n表示的是n[0]的地址。
	*/
    //下面验证一下:
	printf("数组名n的值:%p\n", n);
	printf("n[0]的地址 %p\n", &n[0]);
	printf("n[0]的值 %p\n", n[0]);
	printf("abcedf的地址:%p\n", "abcdef");

	for (int i = 0; i < 2; i++)
	{

		printf("数组n %s\n", *(n + i));
		/*
		结果却是依次输出了abcdef和BC,字符串数组指针和字符串指针的使用是不同的,加了*后再输出才是字符串,不是单个字符
	   为什么呢,注意区分字符串和字符串数组,字符串数组的数组名实际上是一个二级指针,使用*解引用之后才是一个一级指针,才能搭配%s使用!
	 		*/
	}

	for (int i = 0; i < 2; i++)
	{

		printf("数组n %s\n", (n + i));
		//这样输出是乱码,相当于输出的是第二个元素所在的地址
	}
	printf("**********************\n");

	printf("看看对于字符串能不能用指针一次性输出\n");

	const char* g = "abcde";


	printf("pointer g 表示的字符串:%s\n", g);//输出abcde

	printf("pointer g 表示的字符:%c\n", *g);//打印字符串的首字符a


	printf("%c\n", *"ABC");//A

	printf("%c\n", "ABC");//???没有什么意思,输出一个不知道什么的值

	//下面需要看一下字符串数组在内存中的存储方式

	const char* name[] = { "ABC", "BCD", "DEC" };

	for (int i = 0; i < MAX; i++)
	{
		printf("数组name:\n name[%d]=%c\n", i, *(name[i]));
		
		//依次输出A、B、D
	}

	for (int i = 0; i < MAX; i++)
	{
		printf("数组name:\n name[%d]=%s\n", i, (name[i]));
		//依次输出ABC、BCD、DEC


	}

	printf("**********************\n");


	//printf("%s\n", *("AB"));//wrong,程序不运行,%s不能搭配字符使用
	//printf("%s\n", "A");//输出A
	printf("%c\n", *"AB");//A
	printf("%c\n", *"A");//A

	printf("%s\n", "ABC");//ABC
	printf("**********************\n");

	char d[5] = "hello";//字符串本身就是一个数组

	printf("%s\n", d);//乱码 hello后面跟一堆垃圾值,因为在分配的空间中没有结束字符\0

	//	注:%s后面跟的,可以是字符串指针,或者字符数组名。
	/*
	字符串就是字符组成的数组,但是后面多了一个结束符号\0;
	别字符串指针写多了,再写成char a="abc",应该是char a[]="abc"...*/

	return 0;
}

要注意字符串数组的数组名是一个“地址的地址”,要*之后才能搭配%s输出字符串,字符串指针const char* 直接搭配%s即可输出字符串。

以此类推,凡是指针数组,数组名都是相当于一个"二级指针",如果想用数组名输出数组元素时,使用解引用*后才得到一个一级指针。

如:

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

int main(int argc, char* agrv[])
{

	const char* names[] = { "a", "b", "c" };

	for (int i = 0; i < 3; i++)
	{
		printf("name[%d]=%s\n", i, names[i]);//这是直接用数组元素输出各个数组成员,数组元素本身就是一级指针。
	}
	
	//下面看一下如果用数组名输出各个数组元素,需要采用指针移位的方式,而且因为指针数组的数组名是相当于一个二级指针,要使用*进行解引用才可以。

	const char* m[] = { "as", "bs", "cs" };

	for (int i = 0; i < 3; i++)
	{
		printf("m[%d]=%s\n", i, *(m + i));
	}

//输出首字母
//可以看出,如果想要输出单个字符,%c后面配合的应该直接是字符变量或者字符指针的解引用。
//这与%s输出字符串是不同的,根本原因还是在于字符串本身就是数组,字符却不是一个数组。
const char* s[] = { "as", "bs", "cs" };

	for (int i = 0; i < 3; i++)
	{
		printf("s[%d]=%c\n", i, **(s + i));
	}
	return 0;
}

其实说了这么多,关键就在于%s后面跟的应该是一级指针,如果用指针数组名输出数组元素,要解引用,使用*指针数组名,才能搭配%输出正确的字符串。如果直接使用指针数组的成员,也就是直接使用指向字符串的指针,那么直接%s,指针数组名[i]就可以了。实际上,数组名也是一个指针常量呢,其实就是一个地址,相当于%s,后面接的就是指向字符串的指针。

下面再运行一下这些程序看看结果,加深对指针,数组,数组名,字符以及字符串的认识。

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




int main(int argc, char* agrv[])
{
	
	int array[3] = { 1, 2, 3 };

	int* arr = array;
	
	int size = sizeof(array)/sizeof(int);
	for (int i = 0; i < 3; i++)
	{
	printf("array[%d]=%d\n",i, *(arr+i));
	printf("arrar[%d]=%d\n", i, *(array + i));
	
	}
	
	
	char s[3][4] = { { "Abc" }, { "Bcd" }, { "Cde" } };//字符串数组其实是一个二维数组

	char w[] = { 'A', 'B', 'C' };

	char n[] = "abc";
	//上面三个全都是在栈区中的,在栈区中放了这些字符。
	char* ps[] = {s[0],s[1],s[2]};
/*指针数组才能指向字符串数组,一个单独的指针不能指向一个字符串数组!一个单独的指针只能指向一个字符串,字符串本身就是一个字符数组,所以一个指针变量只能指向一个数组,指向二维数组的应该是指针数组才可以*/

	char* pw = w;

	char* pn = n;

	for (int i = 0; i < 3; i++)
	{
		printf("s[%d]=%s\n", i, *(s + i));
        printf("s[%d]=%s\n", i, *(ps + i));//指针和数组名都有p+1指向下一个元素的用法,因为数组名本身也是一个指针常量
		printf("s[%d]=%s\n", i, s[i]);
		printf("s[%d]=%s\n", i, ps[i]);

		printf("w[%d]=%c\n", i, *(w + i));
		printf("w[%d]=%c\n", i, *(pw + i));

		printf("n=%s\n", n);
		printf("n=%s\n", pn);
		printf("n[0]=%c\n", *pn);
	}


	return 0;
}

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小哇123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值