1.初阶指针内容回顾
1.内存被划分为小的内存单元,每个内存单元都有一个编号,这个内存编号就是所谓的地址,也被叫做指针(内存编号=地址=指针)。
2.指针变量是一个变量,存放的是地址,地址能够唯一标识一块内存单元。
3.指针变量大小是固定的4/8个字节(32/64位平台上)。
4.指针变量类型决定了(1)指针在+-整数时的跳过多少个字节;(2)指针在解引用的时候访问的权限。
2.字符指针
2-1 字符指针长什么样?
int main() { //代码一: char ch = 'a'; char* p1 = &ch; printf("字符'a'的地址:>%p\n", p1); printf("对指针解引用得到的是指针指向的那个目标:>%c\n", *p1); printf("\n\n\n"); //代码二: char* p2 = "hello world"; printf("字符'h'的地址:>%p\n", p2); printf("对指针解引用得到的是指针指向的那个目标:>%c\n", *p2); printf("%s\n", p2); return 0; }
2-2 误区:
误以为代码2中p2指针变量是存放着字符串,实际上p2所指向的是字符串"abcdef”中首个字符'a'的地址(原因有两点:1.指针变量在x86位(32位机器下)是4个字节,但是"abcdef“有7个字符,一个指针只能存放一个地址;2.通过指针解引用打印出'a'),同时因为字符串"abcdef"在内存(字符常量区)中的空间是连续的,所以只要拿到字符串首个元素'a'的地址就可以访问到整个字符串的内容。
2-3 代码一和代码二的异同:
1. 同:
(1)指针类型:p1和p2都是字符指针变量,都是存放的是字符a的地址。
(2)打印字符'a:打印出'a'都是通过拿到字符指针变量内存放的地址进行解引用,得到的都是指针变量所指向的那个变量。
2. 异
(1)字符'a'的存储位置:代码1中的'a'存放在栈区,代码2中的'a'存放在字符常量区(通过下方截图可以证明)
2-4 关于字符常量区:
对于上图的解释3:
- 既然位于字符常量区的"abcdef"是不允许修改的
那么在p2指向这块内存空间的时候就会产生隐患,一旦通过解引用试图修改就会造成程序的运行时错误,程序瘫痪;
- 因此使用const修饰(也就是const char* p2="abcdef")来阻止对指针解引用试图修改的行为 ,及时给出编译时错误,程序压根编译不通过。
2-5 一道为了区分栈区和字符常量区&&字符数组和字符指针的面试题:
int main() { const char* ptr1 = "abcdef"; const char* ptr2 = "abcdef"; char arr1[] = "abcdef"; char arr2[] = "abcdef"; if (ptr1 == ptr2) { printf("ptr1==ptr2\n");//bingo } else { printf("ptr1!=ptr2\n");//error } if (arr1 == arr2) { printf("arr1==arr2\n");//error } else { printf("arr1!=arr2\n");//bingo } return 0; }
3.指针数组
其实下面要讲的指针数组和数组指针都是一种类型(类似整型,double,float)
3-1 指针数组长什么样捏?
//整型数组 int arr1[5]={1,2,3,4,5};//存放整型的数组 //字符数组 char arr2[5]={'a','b','c,''d','\0'};//存放字符的数组 //指针数组:指针是修饰,数组是名词,主角 int* arr3[5]={&arr1[0],&arr1[1],&arr1[2] ,&arr1[3] ,&arr1[4]};//存放指针的数组 //指针数组的意义:看着食之无味,弃之可惜 //实际上作用大着捏,我们指针数组的意义和普通数组的意义类似, //都是对方便对相同类型元素(在这里的类型元素是指针)统一处理:比如修改和打印
3-2 初级使用(或者说给你看一下基本使用):
int main() { //简单用法: int a = 10; int b = 20; int c = 30; //没有数组指针的情况 int* p1 = &a; int* p2 = &b; int* p3 = &c; //有数组指针的情况 int* arr[3] = { &a,&b,&c }; for (int i = 0; i < 3; i++) { printf("%d\n", *(arr[i])); } return 0; }
3-3这才是指针数组的正确使用方法!【指针数组模拟打印二维数组】
这和arr[3][5]的区别在于arr[3][5]在内存中中每一个元素的地址都是连续的,而指针数组模拟的二维数组这种方式的地址不是连续的。
int main() { int arr1[5] = { 1,2,3,4,5 }; int arr2[5] = { 2,3,4,5,6 }; int arr3[5] = { 3,4,5,6,7 }; int* arr[3] = { arr1,arr2,arr3 }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { //printf("%d\t",arr[i][j]);//way1 //printf("%d\t", *(arr[i] + j));//way2 printf("%d\t",*(*(arr+i)+j);//way3 //实际上way1和way2在编译器翻译过程中会自动转换为way3 } printf("\n"); } return 0; }