当前位置:网站首页>【进阶指针一】字符数组&数组指针&指针数组
【进阶指针一】字符数组&数组指针&指针数组
2022-06-12 08:26:00 【每天都要坚持刷题】

目录
2-5 一道为了区分栈区和字符常量区&&字符数组和字符指针的面试题:
3-3这才是指针数组的正确使用方法!【指针数组模拟打印二维数组】
4-5 这才是数组指针的正确使用方法捏【数组指针模拟打印二维数组】
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;
}


4. 数组指针
int main()
{
//整型指针-指向整型的指针-存放整型变量的地址
int a = 10;
int* pa = &a;
//整型指针-指向字符的指针-存放字符变量的地址
char ch = 'w';
char* pc = &ch;
//数组指针-指向数组的地址,存放数组变量的地址
int arr[5] = { 1,2,3,4,5 };
int(*p)[5]=&arr;//注意这个5不能省略,因为这个5是指针指向的那个数组的类型
} 
一个指针只能存放一个地址,只不过这个地址是整个数组的地址
4-1 区分取地址数组名和数组名(老生常谈了)

4-1-1 sizeof(数组名):求的是该类型所定义的变量在内存中所占空间的大小,单位是字节。
int main()
{
int arr1[5] = { 1,2,3,4,5 };
printf("%d\n", sizeof(arr1));//32位平台下:20字节 64位平台下:20字节//类型;int[5]数组
printf("%d\n", sizeof(arr1+0));//32位平台下:4字节 64位平台下:8字节//已经不是单独的sizeof(数组名)//类型:int*指针
printf("%d\n", sizeof(arr1[0]));//32位平台下:4字节 64位平台下:8字节//类型:int*指针
return 0;
}4-1-2 &数组名,在没有+-整数时虽然地址是相同的,但是意义不同。

4-2 辨析数组指针和指针数组
图图我就省略喽!
int main()
{
//我们知道:去掉变量名剩下的部分就是变量所属的类型
//(这里可以通过调试得以验证以下猜想)
//整型数组,数组类型为int [5],从左往右念就是整型数组
//特别注意:数组索引中的元素个数5也是类型的一部分
//所以int [4]和int [5]所属的是不同的类型
int arr[5] = { 1,2,3,4,5 };
//p1先和方块5(也就是[5])结合,所以整体来看p1是一个数组
//既然是数组我们关心的就是数组呢存放的是什么?
//数组内有五个元素,每个元素的类型是int* 类型
//所以变量p1的类型为int* [5],从左往右念就是指针数组
int* p1[5] = { arr,&arr[1] ,&arr[2], &arr[3], &arr[4] };
//p2先和*结合,所以整体来看p2是一个指针
//既然是指针,我们关心的就是指针指向的是什么?
//指针指向的是一个数组,数组内有五个元素,每个元素时int类型
//所以变量p2的类型为int[5]*,从左往右念就是数组指针
int(*p2)[5] = &arr;
return 0;
}
4-3 学会了?来看一个小测试题


4-4 来看一个脱裤子放屁的代码【看一看数组指针的使用】
void Print1(int arr[], int sz)
{
printf("Print1:\n");
for (int i = 0; i < sz; i++)
{
printf("%d\t", arr[i]);
}
}
void Print2(int* arr, int sz)
{
printf("Print2:\n");
for (int i = 0; i < sz; i++)
{
printf("%d\t", arr[i]);
}
}
void Print3(int(*p)[5],int sz)
{
printf("Print3:\n");
for (int i = 0; i < sz; i++)
{
printf("%d\t", *((*p)+i));
//printf("%d\t", (*p)[i]);
}
}
int main()
{
int arr[5] = { 1,2,3,4,5 };
int sz = sizeof(arr) / sizeof(arr[0]);
//写一个函数打印数组内容
//测试1:
Print1(arr, sz);
printf("\n");
//测试2:
Print2(arr, sz);
printf("\n");
//测试3:
Print3(&arr,sz);
return 0;
}

4-5 这才是数组指针的正确使用方法捏【数组指针模拟打印二维数组】
指针数组虽然可以int(*p)[3]=&arr;其中arr是一个一维数组,但是这样太鸡肋了,
还不如直接int*p arr;
指针数组真正的使用场景是留给二维数组传数组名时,形参用指针数组接收。
void Print1(int arr[3][5], int row, int col)
{
printf("Print1:\n");
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d\t", arr[i][j]);
}
printf("\n");
}
}
void Print2(int(*p)[5], int row, int col)
{
printf("Print2:\n");
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d\t", (* (p + i))[j]);
//printf("%d\t", *(*(p+i)+j));
//printf("%d\t",p[i][j]);
//p+i是第i行,也就是第i行整个数组的地址
//*(p+i)也就是对整个数组的地址解引用,就是第i行的数组名,也就是第i行首元素的地址
//*(p+i)+j就是第i行第j列元素的地址
//*(*(p+i)+j)也就是对第i行第j列元素的地址解引用,就是第i行第j列的元素
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
//测试1:
Print1(arr, 3, 5);
printf("\n");
//测试2:
Print2(arr, 3, 5);
printf("\n");
return 0;
}
上面目前讲的基本还是数组指针指向的是一个一维数组
其实数组指针还是可以指向一个二维数组:
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
int(*p)[3][5]=&arr;
完结,撒花,等等,要不来一个小测试?
5 测试题和规律总结
测验1:
如果int(*arr[3])[5];
问题:怎么理解这个代码?
答案:数组指针数组



测验2:那么指针数组指针?

我总结的一点小规律
如果光要给上面这个东西命名的话,只用关注*和[]的出现次序排列就可以了
比如;数组指针数组:[]*[]
指针数组指针*[]*
然后再把[]存的内容和*指向的东西往里面填进去就可以了
边栏推荐
- The era of post MES system has come gradually
- MYSQL中的查询
- What exactly is APS? You will know after reading the article
- Never use MES as a tool, or you will miss the most important thing
- Vision Transformer | Arxiv 2205 - TRT-ViT 面向 TensorRT 的 Vision Transformer
- Discrete chapter I
- (P36-P39)右值和右值引用、右值引用的作用以及使用、未定引用类型的推导、右值引用的传递
- (P19-P20)委托构造函数(代理构造函数)和继承构造函数(使用using)
- What should be paid attention to when establishing MES system? What benefits can it bring to the enterprise?
- Hands on deep learning -- image classification dataset fashion MNIST
猜你喜欢

Convolutional neural network CNN based cat dog battle picture classification (tf2.1 py3.6)

What exactly is APS? You will know after reading the article

工厂的生产效益,MES系统如何提供?

MATLAB image processing -- image transformation correction second-order fitting

How to understand the production scheduling of APS system?

vm虛擬機中使用NAT模式特別說明

What is the MES system? What is the operation process of MES system?

visual studio2019的asp.net项目添加日志功能

Face recognition using BP neural network of NNET in R language

Hands on learning and deep learning -- a brief introduction to softmax regression
随机推荐
Hands on deep learning -- implementation of multi-layer perceptron from scratch and its concise implementation
Vision transformer | arXiv 2205 - TRT vit vision transformer for tensorrt
What should be paid attention to when establishing MES system? What benefits can it bring to the enterprise?
企业上MES系统的驱动力来自哪里?选型又该注意哪些问题?
(P33-P35)lambda表达式语法,lambda表达式注意事项,lambda表达式本质
Lock mechanism in MySQL
What kind of sparks will be generated when the remote sensing satellite meets the Beidou navigation satellite?
Ankerui motor protector has the functions of overload inverse time limit, overload definite time limit, grounding, starting timeout, leakage, underload, phase failure, locked rotor, etc
The Three Kingdoms kill the surrounding areas -------- explanation of the pig Kingdom kill problem
2.1 linked list - remove linked list elements (leetcode 203)
MATLAB image processing -- image transformation correction second-order fitting
Record the first step pit of date type
MPLS的原理与配置
How to write simple music program with MATLAB
ctfshow web 1-2
MYSQL中的锁的机制
MSTP的配置与原理
Hands on learning and deep learning -- Realization of linear regression from scratch
(P15-P16)对模板右尖括号的优化、函数模板的默认模板参数
What is the difference between ERP production management and MES management system?