当前位置:网站首页>C指针进阶1-->字符指针,数组指针,指针与数组传参,函数指针
C指针进阶1-->字符指针,数组指针,指针与数组传参,函数指针
2022-06-29 22:48:00 【real Wangyanbin】
字符指针
我们在C语言指针部分学习到了指针就相当于是一个地址,指针变量就是存放地址的变量,指针变量的类型就决定着对指针操作时指针操作的精度。±操作指针跳过的大小与指针的类型有着密切的关系,所以什么类型的指针变量就存储什么类型的地址(就是该地址中存储数据的数据类型)。我们口头说的指针就是指针变量。
字符指针顾名思义他就是存储字符类型所在空间的地址,是指向字符类型的指针。字符指针所存储的地址主要有两种不同的形式,
char ch = ‘W’;
char * pc = &ch;
//此种情况就是最为直接的一种—>存放一个字符变量的地址char *pc = “abcdef”;
//存放字符串常量的首地址,相当于—>存放字符串常量
字符指针存放字符串常量的时候,是不是和字符数组很像:
- 字符数组名等价于数组首元素的地址,字符指针变量名存放的是字符串的首地址。
- 字符指针和字符数组名都可以用[]来遍历。
但是他们是有差异的,主要有两点:
字符数组中的数组元素可以改变,但是字符指针所指向的字符串常量是不能改变的,因为字符串常量是一个常量,常量值不能改变。但是字符指针所存储的字符串常量是可以变换的。
int arr[] = “abcdef”
int *pc = “abcdef”;
arr[2]=‘F’;//YES
pc[2] = ‘F’;//ERROR
arr = “ABCDEF”;//ERROR
pc = “ABCDEF”;//YES字符指针存储的是字符串常量的地址,多个不同的字符指针所存储的相同的字符串常量所存储的地址相同。字符数组是存储字符串的,存储相同的字符串的不同的字符数组首元素的地址是不同的
看一个例题:#include<stdio.h> int main() { const char* p1 = "abcdef"; const char* p2 = "abcdef"; char arr1[] = "abcdef"; char arr2[] = "abcdef"; if (p1 == p2) printf("p1==p2\n"); else printf("p1!=p2\n"); if (arr1 == arr2) printf("arr1 == arr2\n"); else printf("arr1 !=arr2\n"); return 0; }上述例题最终结果:
p1==p2
arr1 != arr2
数组指针
数组名与数组指针
我们在C语言指针部分学习了指针数组(详情请看C语言指针初阶),指针数组是指针修饰数组,是一个存放指针类型的数组。数组指针是数组修饰的是指针,这种数据类型就是属于指针,是指针变量中存放的是数组类型的地址。这个数组类型的地址是什么意思,我们先来回忆一下数组名。
数组名是数组首元素的地址,但是有两种情况特殊
- sizeof(数组名);
- &数组名
上述两种数组名代表整个数组的地址,&数组名 取出来的地址是整个数组的地址,数组指针就是指向数组类型的指针,所以数组指针所存储的就是 &数组名
数组指针的格式: int (*pc)[10] ;
- //pc先和结合,说明pc是一个指针变量,然后指针指向的是一个大小为10个整型的数组。所以pc是一个指针,指向一个数组,叫数组指针。数据类型为 int ()[10];
- 特别注意要和:int *p[10];做区分,p先与[]结合,说明p是一个数组,数组中的元素类型是int * 。p的数据类型为 int *[10];
数组指针的应用
1.用数组指针遍历数组
#include<stdio.h>
int main()
{
int arr[] = {
1,2,3,4,5,6,7,8,9,10 };
int(*p)[10] = &arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("%d ", *(*p + i));
}
return 0;
}
- p是指向数组的,*p其实就相当于数组名,数组名又是数组首元素的地址
所以*p本质上是数组首元素的地址
但是这种遍历看着比较复杂,直接用整形指针和数组名遍历不是更加方便吗?
其是数组指针是可以这样用,但不是主要的用途,数组指针主要还是用来函数的传参。
2.用数组指针作为形参接收二维数组
#include<stdio.h>
void print(int(*p)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%d ", p[i][j]);//*((p+i)+j)<==>p[i][j]
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
print(arr,3,5);
return 0;
}
二维数组名arr代表二维数组首元素的地址,二维数组首元素就是二维数组的第一行相当于一个一维数组的地址,所以可以用数组指针接收。
数组指针概念练习
int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];
前三行可以很容易的看出来是 数组 指针数组 数组指针。
主要是第四行的,parr3[10]可以看出他是一个数组 去掉parr3[10]得到的int (*)[5]是该数组的元素类型。所以该代码的意思是一个有10个int (*)[5]元素类型的数组,也可以说是存放数组指针的数组。
数组参数、指针参数
在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?
一维数组传参
#include <stdio.h>
void test(int arr[])//ok?
{
}
void test(int arr[10])//ok?
{
}
void test(int* arr)//ok?
{
}
void test2(int* arr[20])//ok?
{
}
void test2(int** arr)//ok?
{
}
int main()
{
int arr[10] = {
0 };
int* arr2[20] = {
0 };
test(arr);
test2(arr2);
}
上述几个函数形参是正确的能顺利接受实参。
二维数组传参
void test(int arr[3][5])//1.ok?
{
}
void test(int arr[][])//2.ok?
{
}
void test(int arr[][5])//3.ok?
{
}
void test(int* arr)//4.ok?
{
}
void test(int* arr[5])//5.ok?
{
}
void test(int(*arr)[5])//6.ok?
{
}
void test(int** arr)//7.ok?
{
}
int main()
{
int arr[3][5] = {
0 };
test(arr);
}
二维数组传参,函数形参的设计只能省略第一个[]的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。
所以函数1,3形参正确,2形参错误
二维数组名代表二维数组首元素的地址,也就是第一行数组的地址,相当于一个数组名,应该用数组指针来进行接收,4.整形指针错误,5.指针数组错误,6数组指针正确。
对于第七个传参问题,有的同学以为二级指针嘛不就是地址的地址嘛,其实是不正确的,二维数组是存放一级指针变量的地址,而二维数组名是一维数组的地址,所以是错误的。
一级指针传参
如果函数的形参是一级指针,那么可以给函数传参的实参是:数组名,一级指针,变量取地址,以及二级指针解引用(少用);
void print(int* p)
{
}
int main()
{
int a = 10;
int arr[] = {
1,2,3,4,5,6,7,8,9,10 };
int *pa = &a;
int** ppa = &pa;
print(pa);
print(arr);
print(&a);
print(*ppa);
return 0;
}
二级指针传参
二级指针传参一般有三种情况:二级指针,一级指针取地址,指针数组名;
指针数组数组名代表首元素的地址,首元素是指针,所以指针数组名是二级指针
void test(int** p)
{
}
int main()
{
int a = 0;
int* pa = &a;
int** ppa = &pa;
int* parr[10];
test(ppa);
test(&pa);
test(parr);
return 0;
}
函数指针
前面的数组指针,二级指针等都是指向各种类型的数据,但是C语言指针并不是只能指向各种数据,也能指向函数。函数也占据内存空间,其中函数名可以作为函数所占用空间的首地址,&函数名代表是函数所在空间的首地址。
#include<stdio.h>
void test()
{
printf("hello world");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
数组指针是指向数组的指针,整形指针是指向整形的指针,由此推断函数指针是指向函数的指针。
函数指针形式:void (*pfun1)();
其中有很容易混淆的:void *pfun2(); ()的结合性要比*强,所以该代码的意思就是声明一个返回值为void *的函数。
两个有趣的代码
//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);
代码1:是一个函数调用,是调用0为地址的函数
- 把0强制类型转化为void (*)()–>无参返回类型为void的函数的地址
- 调用0地址处的函数
代码2:
signal是函数名,以上代码是一次函数声明。
声明的signal函数第一个参数类型是int,第二个参数类型是函数指针,该函数指针指向的函数参数是int,返回类型是void,signal函数的返回类型也是一个函数指针,该函数指针指向函数的参数是int,返回类型是void。
代码2太复杂,简化:
typedef unsigned int uint;
typedef void(* pf_t)(int) ;//把void(*)(int)类型重命名为pf_t
边栏推荐
- grpc的开发详解
- Low code, end-to-end, one hour to build IOT sample scenarios, and the sound network released lingfalcon Internet of things cloud platform
- Hematemesis finishing: a rare map of architects!
- Constexpr function
- Why does copying files on a shared folder on a local area network (ERP server) result in the loss of the local Internet
- PhpSpreadsheet读写Excel文件
- Laravel 创建自己的 Facade 扩展 geoip 根据 IP 获取国家、地域、城市信息
- mysql备份数据库linux
- Uniapp copy contents to clipboard
- Touch key and key control corresponding LED status reversal
猜你喜欢

Optional类的高级使用
详细聊聊MySQL中auto_increment有什么作用

redis客户端

Discussion on distributed unique ID generation scheme

众昂矿业:萤石助力氟产业锂电建设发展

How to solve the problem that the computer time is not automatically updated after proofreading

Code sharing for making and developing small programs on the dating platform

One click file sharing software jirafeau

5-1系统漏洞扫描
![Realizing deep learning framework from zero -- RNN from theory to practice [practice]](/img/a0/d64b69dec4a8f3a3dbc2eb47df9372.png)
Realizing deep learning framework from zero -- RNN from theory to practice [practice]
随机推荐
Still stay up late every day and work overtime to make statements? In fact, you don't know how to make reports efficiently
MySQL lock common knowledge points & summary of interview questions
Go zero micro Service Practice Series (VII. How to optimize such a high demand)
[从零开始学习FPGA编程-51]:高阶篇 - 基于IP核的FPGA开发- 什么是FPGA IP核(软核、固核、硬核)与学习方法
Grep tool
Phpspreadsheet reading and writing Excel files
5-1系统漏洞扫描
Low code, end-to-end, one hour to build IOT sample scenarios, and the sound network released lingfalcon Internet of things cloud platform
从零实现深度学习框架——LSTM从理论到实战【理论】
Talk about auto in MySQL in detail_ What is the function of increment
Vs2013 how to make the program run on other computers
With the rise of China's database, Alibaba cloud lifeifei: China's cloud database has taken the lead in various mainstream technological innovations abroad
5 - 1 Analyse de vulnérabilité du système
Become the only key
Wechat applet: picture seconds plus watermark generation
开源了 | 文心大模型ERNIE-Tiny轻量化技术,又准又快,效果全开
NRM explanation
MySQL 锁常见知识点&面试题总结
sql刷题595. 大的国家
云原生爱好者周刊:炫酷的 Grafana 监控面板集合