指针理解——初步
转载注明出处:https://www.cnblogs.com/kelamoyujuzhen/p/9349963.html
指针变量的大小
什么样的类型变量就是用来存储什么样的类型数据。整形,整形指针类型等等都是变量类型。
源码
1 #include <stdio.h> 2 int main() 3 { 4 printf("——————————\n"); 5 printf("sizeof(char)=%d\n",sizeof(char)); 6 printf("sizeof(short)=%d\n", sizeof(short)); 7 printf("sizeof(int)=%d\n", sizeof(int)); 8 printf("sizeof(float)=%d\n", sizeof(float)); 9 printf("sizeof(double)=%d\n", sizeof(double)); 10 printf("——————————\n"); 11 printf("sizeof(char*)=%d\n", sizeof(char*)); 12 printf("sizeof(short*)=%d\n", sizeof(short*)); 13 printf("sizeof(int*)=%d\n", sizeof(int*)); 14 printf("sizeof(float*)=%d\n", sizeof(float*)); 15 printf("sizeof(double*)=%d\n", sizeof(double*)); 16 printf("——————————\n"); 17 18 getchar(); 19 return 0; 20 }
运行结果:
各种指针变量类型到底是占4Byte还是8Byte,视“配置管理器”是x86平台还是x64平台。
前面说到“整形,整形指针类型等等都是变量类型”。为啥会这么说,并不是挖字眼。 对于变量存储数据,这一点大家都同意。指针变量也是变量,只是他比较特殊,存储的是某种类型变量的地址。而我们说指针,其实说的是地址。
多级指针指向分析
稍微复杂点一个例子
1 #include <stdio.h> 2 int main() 3 { 4 int a = 10; 5 int b = 20; 6 int *p = NULL; 7 int **s = NULL; 8 9 p = &a; 10 s = &p; 11 *p = 100; 12 *s = &b; 13 14 getchar(); 15 return 0; 16 }
图解:
这里我们假定像int a这种普通定义变量,称为0级指针。则有:
①一级指针 = &零级指针
②二级指针 = &一级指针
③*二级指针 = &零级指针
①与③实际上是一回事。对多级指针使用*是在降级
指针变量具有二值性
指针变量,指针 概念之所以不好理解,是因为相对于普通变量类型(eg 整形),指针变量具有二值性(自身的值,指向的值)。
普通类型常量,不允许更改其值。源码
1 #include <stdio.h> 2 int main() 3 { 4 const int a = 10; 5 a = 5; 6 getchar(); 7 return 0; 8 }
a是常量,在定义常量的时候初始化为10。稍后a赋值为5。由于常量不可以修改,所以这段代码编译不过。
倘若定义常量但没有初始化,直接使用其值呢? 编译不报错,运行有问题。源码
1 #include <stdio.h> 2 int main() 3 { 4 const int a ; 5 printf("%d",a); 6 getchar(); 7 return 0; 8 }
所以对于常量的使用,需要在定义的时候初始化。
指针类型常量,由于指针具有二值性(指针自身的值 和 指针指向的值)。随意const对这两个值分别做出了限制
const int * p; int const * p; int * const p; const int * const p;
记忆及区分方法:
以*为分界线,区分到底对什么做了限制。如下图:
举一个例子帮助理解,见下图
第一种情况:限制*p
美女找了个男票,却不能花他的钱。果断绿了他(见绿线),又找了一个男票(见黑线)。不过很不幸,还是不能花新任男票的钱
第二种情况:限制p
美女找了个土豪,可以花他的钱。但是却不能绿了他换新的男票
第三者情况:限制p和*p
美女很悲催,找了个男票,既不能花他的钱,也不可以绿了他。
上面一堆+例子其实都是废话,《C++模板》中对这种情况的解释是,const限制的是他后面的内容。
指针的类型
判断方法:把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型
例如:
int *ptr //指针类型 int *
int (*ptr)[5] //指针类型 int (*)[5]
指针指向的类型
当你通过指针来访问所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待,同时也决定了指针加1的能力
从语法角度看,你只需把指针声明语句中的指针名字和名字左边的指针声明符 * 去掉,剩下的就是指针所指向的类型
例如:
int * ptr //指针所指向的类型是 int
int *(*ptr)[4] //指针所指向的类型是 int *()[4]
指针的值
指针的值 也可以称为 指针所指向的内存区或地址——是指指针本身存储的数值,这个值将被编译器当做一个地址而不是一个一般的数值
一个常见的错误
int *ptr = 0x11123f
0x11123f这里并不是一个地址,他只不过是一个16进制数。和我们接触的10禁止数 eg:250 没有任何区别。修改如下
int *ptr = (int*)0x11123f
指针本身所占内存区域(指针自身大小)
指针本身所占据的内存区——在32位平台里,指针本身占据了4个字节的长度。
在32位平台里,寻址范围2^32。寻址这么大内存需要4Byte,共32bit。也就是说对于指针变量,他只需要4Byte大小空间就可以表示任何一个内存地址空间。
指针与内存四区结合使用
主调函数 与 被调函数
主调函数可把堆区、栈区、全局数据内存地址传给被调用函数
被调用函数只能返回堆区、全局数据
内存分配方式
指针作为函数参数,是具有输入 输出特性的
理解:
输入:指针做函数参数,表示输入参数,主调函数分配内存。这也暗示,不能给NULL,未知地址,常量区的地址赋值
输出:指针做函数参数,表示输出参数,被调用函数分配内存。为保证主调函数在被调函数退出后,被调函数分配的空间仍有效,被调函数需要分配堆空间 或者 常量区空间
被调用函数是在heap上分配内存而非stack上
//操作栈区
#include<stdio.h> #include<string.h> void fun(char* str/* in */) {
if(NULL == str)
return;
char buf[] = "hello"; //给str指向的内存拷贝内容 strcpy(str, buf); } int main(int argc, char* argv[]) { char buf[10] = { 0 }; fun(buf); printf("%s", buf); return 0; }
输出hello
//操作常量区 #include<stdio.h> #include<string.h> void fun(char* str) { char buf[] = "hello"; strcpy(str, buf); } int main(int argc, char* argv[]) { char* buf = "world"; fun(buf); printf("%s", buf); return 0; }
这个代码会引起 Segmentation fault (core dumped) 。其原因是,fun中试图向常量区写数据,导致程序挂掉。
把main里面的char* buf = "world"; 改为 char buf[] = "world"; 就没问题了
//操作堆区 #include<stdio.h> #include<string.h> void fun(char* str) { int i = 0; char* buf = (char *)malloc(sizeof(char) * 5); for (; i < 5; ++i) { *buf + i = '#'; } strcpy(str, buf); } int main(int argc, char* argv[]) { char* buf = "world"; fun(buf); printf("%s", buf); return 0; }
这个代码会引起 Segmentation fault (core dumped) 。其原因和上面分析一样。初次之外,fun里面malloc申请的堆内存没有人回收,最终会导致内存泄漏。
指针做输出的情况
#include<stdio.h> #include<string.h> void fun(char** str/*out*/,int* len/* out */) { //只要有变量,变量的地址不可能为空 if (NULL == str || NULL == len) return; char* tmp = (char*)malloc(sizeof(char) * 5); if (NULL == tmp) return; strcpy(tmp, "hello"); //间接赋值 *str = tmp; *len = strlen(tmp); } int main(int argc, char* argv[]) { char* str = NULL; int len; fun(&str,&len); printf("%s %d\n", str,len); return 0; }
结果hello 5