- 指针数组
int a = 11;
int b = 22;
int c = 33;
int* brray[3]; //指针数组的定义,*号在数组名前,有三个指针,分别如下:
//将3个毫无联系的变量给结合到了一块
brray[0] = &a;
brray[1] = &b;
brray[2] = &c;
for(i = 0; i < 3; i++){
printf("%d ", *(brray[i]));
}
/*int *p;
p = array;
for(i = 0; i < 3; i++){
printf("%d ", *p++);
}*/ //*p不叫做指针数组,它是整形变量指针,刚好指向了数组首地址
运行结果:11 22 33
- 数组指针
int array[3] = {1, 2, 3};
int (*p)[3]; //数组指针的定义, 强调的是类型,数组的个数
p = array;
int *p2;
p2 = array;
printf("array的地址:%p\n", array);
printf("array的地址:%p\n", &array[0]);
printf("p的地址:%p\n", p);
printf("p2的地址:%p\n", p2); //四个地址全部为000000000061FDF0
printf("***********注意区别来了************\n");
printf("++p的地址:%p\n", ++p); //p移动后的内存地址为:000000000061FDFC
printf("++p2的地址:%p\n", ++p2); //p2移动后的内存地址为:000000000061FDF4
//ps:数组指针偏移的是整个数组的大小,对于p而言就是3*4=12个字节
//整型变量指针偏移的是一个整型指针大小即4个字节
- 指针需要注意的小细节
(1)指针定义
int *p; //定义指定变量,存放的是变量地址
p = &a; //给指针变量赋值
//*p = &a; //这种定义是错误的
int *p = &a; //*号只有在定义指针的时候,才是指针的标识符,其余时候都是运算符,此时跟+-*/运算符功能相似,表示将变量内存地址中存储的数据值给取出来
(2)指针偏移
int array[3] = {1, 2, 3};
int *p1 = array; //int *p1 = &array[0] 数组首地址:1.数组名;2.数组第一个元素地址
printf("第一个元素地址:%p\n", p1++); //int类型指针偏移4个字节
printf("第二个元素地址:%p\n", p1++);
printf("第三个元素地址:%p\n", p1);
char brray[3] = {'a', 'b', 'c'};
char *p2 = &brray[0];
printf("第一个元素地址:%p\n", p2++); //char型指针偏移占1个字节
printf("第二个元素地址:%p\n", p2++);
printf("第三个元素地址:%p\n", p2);
int *k = (int *)0x0061FDEE;
*k = 24;
printf("k的内存地址为:%p, 存放值为:%d\n", k, *k);
/*
volatile int *k = (volatile int *)0x0061FDEE;
volatile: 类型修饰符:主要作用是,当处于多线程时,A线程可能会对寄存器中的指针变量k的值进行更改
B线程此时可能就不会知道指针k的值已经发生变化了,所以操作系统会使用volatile直接在内存地址中对指针k的值进行读取,从而使得相应计算结果准确无误*/
(3)内存泄漏
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n;
int i;
printf("请输入学生成绩个数:\n");
scanf("%d", &n);
int array[n]; //用数组也可以输入数据并且遍历数据
for(i = 0; i < n; i++){
printf("%d学生成绩:\n", i+1);
scanf("%d", &array[i]);
}
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
putchar('\n');
int *prray = (int *)malloc(n * sizeof(int)); //malloc开辟内存空间
int *p1 = prray;
printf("prray首地址为:%p\n", prray);
for(i = 0; i < n; i++){
printf("请输入第%d个学生成绩:\n", (i+1));
//scanf("%d", &prray[i]); //这样以数组的形式输入可以避免指针偏移对后续结果打印产生影响
//也可以用指针来输入,但需要注意指针偏移对后面结果打印产生的影响
printf("prray[%d]的地址:%p\n", (i), &prray[i]);
scanf("%d", prray);
prray++;
}
putchar('\n');
// prray = &prray[0];这两个偏移前后本来就是相等的,这样是无法使指针指向偏移前的首地址----容易混淆的重点:指针偏移后的首地址与偏移前的首地址是不同的,属于两个不同的地址量
printf("prray偏移后首地址:%p\n", prray);
printf("prray[0]首地址为:%p\n", &prray[0]);
prray = p1; //用中间指针变量将prray重新指向原偏移前的首地址
printf("prray首地址为:%p\n", prray);
for(i = 0; i < n; i++){
printf("第%d个学生成绩为:%d\n", (i+1), *prray++);
}
free(prray);
/*
malloc之内存泄漏:
1.程序跑起来很好,过了几个小时或几周后,程序崩了
2.malloc申请的空间,程序不会主动释放,Linux中的话,程序结束后,系统会回收这个空间
如何避免?
1.注意在循环语句中是否重复申请
2.记得及时合理地释放,即free(p); p = NULL;释放后避免指针p成为野指针,赋值NULL
*/
return 0;
}
运行结果如下:
请输入学生成绩个数:
3
学生1成绩:
89
学生2成绩:
88
学生3成绩:
79
89 88 79
prray首地址为:0000000000B66AE0
请输入第1个学生成绩:
89
prray[0]的地址:0000000000B66AE0
请输入第2个学生成绩:
88
prray[1]的地址:0000000000B66AE8
请输入第3个学生成绩:
79
prray[2]的地址:0000000000B66AF0
prray偏移后首地址:0000000000B66AEC
prray[0]首地址为:0000000000B66AEC
prray首地址为:0000000000B66AE0
第1个学生成绩为:89
第2个学生成绩为:88
第3个学生成绩为:79