指针与函数
指针部分
64位环境 指针类型占用8个字节
32位环境 指针类型占用4个字节
变量与地址
变量对某块内存的抽象表示
指针 -> 地址
变量名 -> 抽象出来的某块空间的别名
指针与指针变量
int i = 1;
int *p = &i; //用于存放整型的指针
int ** q = &p; //*q指的是取q里面的地址值
note
TYPE NAME = VALUE 要区分int *p = &i;
是定义int *
类型的p
,再把p取i
的地址
以下是各变量的值:
i = 1;
&i = 0x2000;
p = 0x2000;
&p = 0x3000;
*p = 1;
q = 0x3000;
&q = 0x4000;
*q = 0x2000; //*q即是p的地址,不用刻意考虑什么多级指针
**q = 1;
tip
指针的大小不取决于数据类型,但是在定义的时候,需要定义数据类型来帮助其在运算的时候读取值的时候获取多少位来代表值。
定义与初始化
空指针与野指针
int *p = NULL; //空指针
int *p = 0x40303; //野指针
tip
空指针(NULL为宏,在预编译的时候补充为((void *)0)
)
danger
如果只定义了int *p
并对其取值,可能会出现段错误,如果你对没有权限赋值的进行赋值的结果,肯定出现段错误。所以如果不确定指针的内容,请把他赋值为NULL
void类型指针
百搭类型,所有类型的值可以赋给他,也可以把他赋给其他类型。
char *s = "hello";
void *i = s; //对字符串指针的赋值
指针运算
& * 关系运算 ++ --
指针与数组
指针与一维数组
#include <stdlib.h>
#include <stdio.h>
int main () {
int a[3] = {1, 2, 3};
// a是常量 p是变量
int *p = a;
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
printf("%p -> %d\n", p+i, *(p+i));
//这里的p+i是指针运算,代表往下数i个的p的数据类型长度
}
}
p+1为什么不是单纯的p变量加一请参考章节指针与指针变量的笔记。同时需要注意,在以上描述中数组
a[i]
,a
是常量,p
是变量
用以下方式可以表示数组:
a[i]: a[i]=*(a+i)=*(p+i)=p[i]
danger
对于p++
-> p = p + 1
;p+1
-> p+1
。由两关系式,可以看出p++ != p+1
#include <stdlib.h>
#include <stdio.h>
int main () {
int a[3];
int *p = a;
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
scanf("%d", p++);
}
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
printf("%d\n", *(p++)); //这里的p变量没有回退到赋值开始地址
}
}
#include <stdio.h>
#include <stdlib.h> //exit(0);
#include <string.h>
#define STRSIZE 1024
int main() {
int a[3];
int *p=a;
int i;
for(i=0;i<sizeof(a)/sizeof(*a);i++){
scanf("%d",p++);
}
for(i=0;i<sizeof(a)/sizeof(*a);i++){
printf("%p->%d\n",&a[i],a[i]);
}
p=a;
for(i=0;i<sizeof(a)/sizeof(*a);i++,p++){
printf("%p->%d\n",p,*p);
}
}
/* 以下是错误输出
1
2
3
0x7ffcc71063a8->1
0x7ffcc71063ac->2
0x7ffcc71063b0->3
0x7ffcc71063ac->1
0x7ffcc71063b0->2
0x7ffcc71063b4->3
*/
tip
以上代码中p++
是放在for语句下,原因是如果printf("%p->%d\n",p,*p++);
写这样的话printf函数是自右向左进行参数压栈计算,会把p自加后赋值给p,导致第一个参数不是我们想要的,需要注意。
数组还可以这样定义:
int *p = (int [3]){1,2,3} //匿名数组
指针与二维数组
二维数组本质上是一维数组的扩展,也是在内存上连续存储,所以不用通过二级指针来定义他,可以通过行列转换进行表示。
tip
a[i][j] = *(*(p+i)+j)
也就是说,数组a[i]
存储了每一行地址,行指针变为列指针(*(p+i)+j
)确定数值的地址。
#include <stdlib.h>
#include <stdio.h>
int main() {
int a[2][3] = {{1, 2, 3},{ 4, 5, 6}};
int (*p)[3] = a;
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
for (int j = 0;j < sizeof(*a)/sizeof(**a);j++) {
printf("%d ", *(*(p+i)+j));
}
}
}
#include <stdlib.h>
#include <stdio.h>
int main() {
int a[2][3] = {{1, 2, 3},{ 4, 5, 6}};
int *p = &a[0][0];
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
for (int j = 0;j < sizeof(*a)/sizeof(**a);j++) {
printf("%d ",*(p+(i * sizeof(*a)/sizeof(**a))+j));
}
}
}