目录
指针是一种数据类型
指针也是一种变量,占有内存空间,用来保存内存地址
变量是内存的编号,而变量本身也是占用内存空间的。如下面的三行代码,a是一个变量,p1也是一个变量,他们都是变量,意思是他们都是要求编译器给他们分配内存而已,只不过是数据类型不一样,就是他们所要求的给它们分配的内存大小不一样而已。哪怕是像第三行前面有一堆的“*”,p2还是个变量,和a和p1没啥区别。
int a = 10;
char *p1 = 100; //分配4个字节的内存
char ****p2 = 100;
测试一下指针变量占用空间大小
printf("a:%d , p1:%d , p2: %d", sizeof(a), sizeof(p1), sizeof(p2));
输出为:
说明,指针变量的大小为4个字节。
*p的含义—操作内存
在指针声明时,*号表示所声明的变量为指针;在指针使用时,*号表示 操作 指针所指向的内存空间中的值
*p相当于通过地址(p变量的值)找到一块内存;然后操作内存
*p放在等号的左边赋值(给内存赋值)
“*”就像一把钥匙 通过一个地址(&a),去间接的修改a变量所表示的内存空间的内容
void main81()
{
int a = 10;
int *p3 = NULL;
p3 = &a;
*p3 = 20; //间接的修改a的值
//*就像一把钥匙 通过一个地址(&a),去修改a变量的标示的内存空间
printf("a:%d , p1:%d , p2: %d", sizeof(a), sizeof(p1), sizeof(p2));
printf("hello...\n");
system("pause");
return ;
}
整个过程描述如下:变量a在栈区开辟了一块内存空间,里面存放数值10(这个数值10不是a开辟空间的大小,只是往里面存的值,a开辟的空间大小仅为4个字节,因为a是int类型的数据结构),变量p3也开辟一块儿内存空间,里面为0(NULL)。“&a”代表取出变量a的地址,赋给p3,那么p3里面的内容就不是NULL了,就是a的地址了,这里假设为0xaa11。再接着,"*p3"中的“*”号就好比是一个钥匙,可以之间访问到p3所包含的内容作为地址,对应的地方。即a的地址,那直接"*p3=20;"等同于间接修改了a的内容了。当然这一切,都得是"*p3"位于等号的左边才可以。
*p放在等号的右边取值(从内存获取值)
同样,接着刚才的程序写,把“*p3”放在等号的右边,让其等于c。这就相当于,从“*p3”对应的内存中取值,放到变量c中。刚才已经说了,“*p3”对应的值是变量a的值,那么这么一搞,c中的值就和a中的值是一样的了。
//*p放在=号左边 写内存
//*p放=号的右边 读内存
{
int c = 0;
c = *p3; //c=20
//*p放在=号左边 写内存
//*p放=号的右边 读内存
printf("c:%d \n", c);
}
运行所看,c的确是20。
指针变量和它指向的内存块是两个不同的概念
{
char *p4 = NULL;
p4 = (char *)malloc(100);
p4 = (char *)malloc(200); //0xcc11
}
上面的三行代码,只想表达一个意思,就是不断的给指针赋值,相当于改变指针方向。
p4被赋值了两次,相当于改变了两次指针方向。 如图所示:
需要牢记的是:
1) 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; p++皆同此理。
2) 给*p赋值*p='a'; 不会改变指针变量的值,只会改变所指的内存块的值
3) =左边*p 表示 给内存赋值, =右边*p 表示取值 含义不同,切记切记!
4) =左边char *p
5)保证所指的内存块能修改(如果想修改指针所指向的内存空间的值,要先保证这个值可以被修改,否则,一修改,肯定报错 )
再举个例子:
char *getStr81()
{
char *tmp = NULL;
tmp = "abcdefgf";
return tmp;
}
void main()
{
char *p = getStr81();
printf("p:%s \n", p);
*(p+2) = 'r'; //经常出现的错误 保证指针所指向的内存空间 可以被修改
system("pause");
return ;
}
这个程序一执行,就会报错,因为tmp="abcdefgf",相当于把数据写入了常量区(全局区)中,这个区域的数据被编译器保护,不可被修改。而*(p+2) = 'r',强制的进行修改,就会报错。这是一个经常犯的错误!
PS:这里我是有疑问的,在最开始的介绍“*p”在等号左边的时候,有过说:“*”就像一把钥匙 通过一个地址(&a),去间接的修改a变量所表示的内存空间的内容,那放在此处,*(p+2)的用法,应该是去修改以p+2内存空间所存放的地址的对应的内存空间,而不是p里面所对应的内存空间吧。
这个理解是错误的!!!!!我想了很久才想明白了。在之前Record5中介绍全局区的内存空间如何和栈区的变量建立关系的时候就已经说过。在全局区里开一个新的内存空间来存常量,把这个常量所存的地址传给对应的变量所开的内存空间里面去,作为其存的值。那么按照这个思路看此例,tmp = "abcdefgf";,变量tmp中存的值并非是“abcdefgf”,而是“abcdefgf”存放在全局区内存位置的首地址。那么后面的,*(p+2),提取的也就是所存的首地址向后数第二个的位置的地址,即“c”,那么*(p+2)='r',就是想把"c"给强制转换成“r”,常量无法被修改,于是,报错。
指针是一种数据类型,是指它指向的内存空间的数据类型
看个例子:
千万不要被多个星给迷住了!
int getABC1(char *p1); int getABC1(char* p1);
int getABC2(char ** p2); int getABC2(char * *p2); int getABC2(char **p2);
int getABC3(char ***p3);
int getABC4(char (*p4)[30]); int getABC4(char (*p4) [30]);
int getABC5(char p5[10][30]); int getABC5(char p5[10][30]);
如何理解这些变量或者或是指针?如何明白每一个代表的是什么含义?
答案是,人怎么理解无所谓,重要的是编译器怎么来理解。在编译器看来,只要你前面加了一个"*"号,那就把你这个变量当成一个指针变量(形参),就给你固定开4个字节的内存空间而已。
当针做函数参数,形参有多级指针的时候, 我们只需要站在编译器的角度 ,只需要分配4个字节的内存(32bit平台)
当我们使用内存的时候,我们才关心指针所指向的内存是一维的还是二维的
p++ == (unsigned char )p+sizeof(a);
指针的数据类型决定了指针的步长,这是指针的理论基础。指针的步长,根据所指内存空间类型来定。
注意:
建立指针指向谁,就把谁的地址赋值给指针。图和代码和二为一。
不断的给指针变量赋值,就是不断的改变指针变量(和所指向内存空间没有任何关系)。
总体代码
dm08_指针铁律1.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main81()
{
int a = 10;
char *p1 = 100; //分配4个字节的内存
char ****p2 = 100;
int *p3 = NULL;
p3 = &a;
*p3 = 20; //间接的修改a的值
//*就像一把钥匙 通过一个地址(&a),去修改a变量的标示的内存空间
{
int c = 0;
c = *p3; //c=20
//*p放在=号左边 写内存
//*p放=号的右边 读内存
printf("c:%d \n", c);
}
{
char *p4 = NULL;
p4 = (char *)malloc(100);
p4 = (char *)malloc(200); //0xcc11
}
printf("a:%d , p1:%d , p2: %d", sizeof(a), sizeof(p1), sizeof(p2));
printf("hello...\n");
system("pause");
return ;
}
char *getStr81()
{
char *tmp = NULL;
tmp = "abcdefgf";
return tmp;
}
/*
int getABC1(char *p1); int getABC1(char* p1);
int getABC2(char ** p2); int getABC2(char * *p2); int getABC2(char **p2);
int getABC3(char ***p3);
int getABC4(char (*p4)[30]); int getABC4(char (*p4) [30]);
int getABC5(char p5[10][30]); int getABC5(char p5[10][30]);
//指针做函数参数 形参有多级指针的时候,
//站在编译器的角度 ,只需要分配4个字节的内存(32bit平台)
//当我们使用内存的时候,我们才关心指针所指向的内存 是一维的还是二维的
*/
void main()
{
char *p = getStr81();
printf("p:%s \n", p);
*(p+2) = 'r'; //经常出现的错误 保证指针所指向的内存空间 可以被修改
system("pause");
return ;
}