C语言 #字符指针


前言

以例子为导向来分析字符指针的中存的是什么,以及常量字符串在内存中是如何存储的。


一、指针概念简述

想要详细地了解指针的概念可以戳此链接(详细的万字讲解):http://t.csdnimg.cn/QL5kk

本文就简单地回顾指针的一些基础知识:

1、指针本身就是地址,内存单元的编号为地址,而地址又称为指针;指针在口语上认为是指针变量、是用来存放地址的变量,每个地址都唯一地标识内存中一块内存空间;

2、指针的大小是固定的4byte\8byte (32位平台或者64位平台)

3、指针是有类型的,其类型不会决定其在内存中占据的空间,而是决定了当解引用此指针变量时有多少字节的访问内存的权限;以及指针变量+、-整数的步长

4、指针的运算

二、字符指针

顾名思义,字符指针就是指针变量指向的对象是字符类型,即指针变量的类型为 char* ;

单个字符的指针创建,代码如下:

#include<stdio.h>

int main()
{
	char ch = 'a';
	char* p = &ch;//此*代表着变量p 为指针变量
	*p = 'b';

	return 0;
}

字符指针可以存放一个字符变量的地址,那么字符串的地址该如何存放呢?

先来看一下整型的例子: 

int a = 10 ;

int b = a + 2;

"a+2" 是一个表达式的话,那么此表达式就一定有自己的值,然后再将此值赋给b ;

注:表达式有两个属性:值属性 和 类型属性

即 "a+2" 的结果为12,那么12就为其值属性;2 为int 类型,变量a 为int 类型,那么 "a+2"此表达式 的类型为int 类型。

eg.char * p = "abcdefg" ;

所以若将字符串"abcdefg"当作表达式,那么将它赋给指针变量p 的是什么呢?在x86环境下,指针p 中只能放大小为4byte 的地址;显然整个字符串在内存中是连续存放的,即不止占用一个内存单元空间,所以整个字符串会有多个地址;那么指针p是存放不下整个字符串的地址‘

字符串"abcdefg"赋给指针p是其首字符 'a '的地址。

而函数printf 的占位符%s 会通过字符串的首字符地址而找到整个字符串;

我们来看一下打印字符串,代码如下:

#include<stdio.h>

int main()
{
	char ch[10] = "abcdefg";
	char* p = "abcdefg";
	char* p1 = ch; //将数组的首元素地址存放起来

	printf("%s\n", "abcdefg");
	printf("%s\n", ch);
	printf("%s\n", p);
	printf("%s\n", p1);

	printf("字符串地址=%p\n", "abcdefg");
	printf("指针p中存放的地址=%p\n", p);
	printf("指针p1中存放的地址=%p\n", p1);

	return 0;
}

代码运行结果如下:

分析:字符串的创建是用字符数组创建的,我们打印字符串一般采用 printf("%s\n", "abcdefg"); 这种方式,或者将字符串存在数组中,然后对此数组进行打印,即printf("%s\n",ch);

这时候你可能就会有疑问了,数组名可以理解为整体的数组也可以理解为其首元素的地址,于是我们就不清楚是printf函数的占位符%s 只要得到字符串的首字符地址就会一直往后访问直到遇到 '\0' ;还是根据的整体字符串"abcdefg"或者整个数组而打印出来整个字符串;

于是我们尝试将数组的首元素地址存放到指针p1中,我们会发现 printf("%s\n", p1);也可以实现打印字符串 "abcdefg" ,那么此时似乎就可以感受到打印字符串只要有其首字符的地址即可;那么将字符串的地址存放到指针p中,指针p中存放的是整个字符串的地址吗?我们知道一个字符在内存中占 1 byte 的空间,而一个内存单元有一个地址,如果是想存放整个字符串的地址,就会存多个地址,但是指针变量在x86环境下只向内存申请了4byte 来存放该地址,所以就无法存放整个字符串的地址;printf("指针p中存放的地址=%p\n", p);的结果看以上代码运行结果,可知p中存放的为一个地址,即字符串首元素的地址;

我们将以上的代码又运行了一次:

我们不难发现,字符串的地址未改变,但是数组首元素的地址改变了;这是因为 "abcdefg" 是一个常量字符串,即不能被修改的字符串;此字符串是存放在内存中的常量区的,在编译期间编译器便指派了地址常量区中的值只能读取而不能修改,所以 当将此存在常量区的字符串的地址存到指针变量中,为以防对此指针变量解引用而对此字符串进行修改,于是应该优化写作: const char* p = "abcdefg";

注:const 修饰指针变量:(eg. char* p = "abcdefg"; )

1、当 const 放在 * 的左边,有两中写法,一是 const  char* p = "abcdefg"; 二是 char const * p = "abcdefg"; 表示 *p即指针p 指向的对象是常变量,也就是说指针p 指向的对象是常变量不可修改;

2、当const 放在* 的右边,写作:char* const p = "abcdefg"; 表示指针变量 p是个常变量即存放在指针p中的地址不可修改;

字符指针有两种的表示形式:

1、char* p = "abcdefg";

2、const char* p = "abcdefg"; \ char const * p = "abcdefg";

二、字符在内存中的存储

我们按照例子来分析:

#include<stdio.h>

int main()
{
	const char* p1 = "abcdef";
	const char* p2 = "abcdef";

	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	if (p1 == p2)
		printf("p1==p2\n");
	else
		printf("p1!=p2\n");

	if (arr1 == arr2)
		printf("arr1==arr2");
	else
		printf("arr1!=arr2");

	return 0;
}

代码运行结果:

分析:常量字符串 ”abcdef“ 存放在内存中的常量区,常量区只能读取而不能对其进行修改;为什么常量字符串存在常量区?因为既然常量字符串不能被修改,那么这样的常量就没必要存多份,只要有一份,大家谁都不能去修改它;所以常量字符串在内存中存一份便足以够用了;所以指针p1 与指针 p2 中存放的地址相同,即p1==p2;

而当数组创建时会向内存申请相对的大小空间来存放数组中的数据;而数组arr1 和 数组arr2 都会向内存申请空间来存放其数据,而每个内存单元的编号都不相同,所以就会导致不同空间的地址在也不相同;再者,数组名代表着首元素的地址,所以 arr1 ! = arr2 ;

注:常量字符串不需要创建;当你写下此代码:const char* p1 = "abcdef"; 的时候,编译器便会在只读数据区中放 abcdef \0 ,便把" abcdef "当作常量字符来看待;而此时,只要将常量字符的起始地址交给一个指针去维护即可;


总结

1、字符指针就是指针变量指向的对象是字符类型,即指针变量的类型为 char* ;

2、const char* p = "abcdefg"; \ char const * p = "abcdefg"; 指针p中存放的是常量字符串在常量区存放的首字符 'a' 的地址

3、常量字符串存放在内存中的常量区,常量区中的数据只能读取而不能被修改。

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值