C语言中多种指针相关类型详解
目录
指针数组
数组指针
arr与&arr的区别
数组指针
1.数组指针的创建格式:
2.数组指针的用处
数组参数,指针参数
一维数组传参
二维数组传参(注意事项)
一级指针传参
二级指针传参
函数指针
函数指针数组
函数指针真正用处用法
指针数组
指针数组是指在一组数中能够存放多个相同指针类型的一组数
指针数组的书写格式:
- int* * *arr[5];——存放int *类型的数组
- char* ch[10];——存放char *类型的数组
- int** pp[5];——存放int** 二级指针类型的数组
当然还可以类比出三级指针,四级指针等等等等....
指针的初始化:
如int* arr[5]={0};
在这里我们将数组arr里的每一个元素赋了0,也就相当于将指针数组里面的所有元素都变为了空指针,这是因为在编译器中,NULL相当于0被强制类型转换为了(void*)类型,所以NULL本质上就是0。
数组指针
数组指针是一种指针类型,是一个指向数组的指针。
数组指针的书写格式:
#include <stdio.h>
int main()
{int arr[5]={0};char s[5]={0};int (*p)[5]=&arr;//这个就是数组指针的格式,//也可以用其他类型如char等char (*b)[5]=&s;return 0;
}
arr与&arr的区别
创造一个int型数组int arr[5]={0}; 我们都知道arr是数组名,也就是首元素的地址,但&arr表示的是什么?
在编译器中输入以下代码:
#include <stdio.h>
int main()
{int arr[5] = { 0 };printf("%p\n", arr);printf("%p\n",arr + 1);printf("%p\n", &arr);printf("%p\n", &arr + 1);return 0;
}
最终输出结果如下:
观察上面的输出后的图,我们可以看到arr与&arr的地址是相同的,但arr与&arr其实是两个完全不同的概念。
我们可以看到,arr+1后的地址与arr的地址相差了4,这是因为arr是数组名,相当于存放了数组首元素的地址,也就是一个int*类型的指针,所以每加一后都会直接跳过四个字节,读取到数组中下一个元素。而我们再看向&arr与&arr+1的地址,经过计算后得到两地址相差的数值大小为20,我们会发现,这刚好是我们创建数组的所占的总共空间大小(20个字节)。
也就是说,&arr其实取到的并不是数组首元素地址,类型并不为int*指针,而取到的是整个数组的地址,类型为数组指针,所以当我们加一的时候,由于是数组指针加一,所以会跳过20个字节。那么数组指针具体又是什么呢?
数组指针
就像int型会有int指针,char类型有char指针,数组也会有对应的数组指针,例如int型数组,数组指针的书写格式就为int(*)[],具体用法如下:
数组指针的应用
1.数组指针的创建格式:
2.数组指针的用处
Ⅰ:访问一维数组
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int(*p)[10] = &arr;int i = 0;for (i = 0; i < 10; i++){printf("%d ",*((*p) + i));}return 0;
}
这里虽然访问一维数组用这种方法繁冗且不建议使用,但还是做下解释。
Ⅱ:访问二维数组
如果要写一个函数,将遍历二维数组将每一个元素打印出来,我们会怎么写呢?
在以前会使用下面的方法:
#include <stdio.h>
void print(int a[3][5], int x, int y)
{int i = 0;int j = 0;for (i = 0; i < x; i++){for (j = 0; j < y; j++){printf("%d ", a[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 };print(arr, 3, 5);return 0;
}
但现在,我们可以用数组指针的方式来实现:
#include <stdio.h>
void print(int(*p)[5], int x, int y)
{int i = 0;int j = 0;for (i = 0; i < x; i++){for (j = 0; j < y; j++){printf("%d ", *(*(p + 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 };print(arr, 3, 5);return 0;
}
在二维数组中例如arr[3][5],其中的“[3]”所代表的是有3行元素,“[5]”代表的是每行元素有5列。而arr[5]则代表一行的地址
所以当我们在传参时,只需要将形参定为int型的指针数组,先将每一行的地址传入,就可以实现遍历数组的作用。
再次理解:
#include <stdio.h>
int main()
{int a[10] = { 0 };int* p = a;//*(a+i)==*(p+i)==a[i]==p[i]
}
数组参数,指针参数
一维数组传参
看下面代码,判断传参是否正确:
#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);return 0;
}
一维数组传参经验总结:
- 在数组传参时可以使用数组形式,而且数组后可以写大小也可不写,因为数组在传参过程中不会创建数组,所以数组大小填错或不填都可以
- 数组传参传入的数组名是首元素地址,可以用指针来接收
所以上述代码中的传参都是正确的。
二维数组传参(注意事项)
看下面代码,判断传参是否正确:
#include <stdio.h>
void test(int arr[3][5])//ok? ----1
{}
void test(int arr[][])//ok? ----2
{}
void test(int arr[][5])//ok? ----3
{}
void test(int *arr)//ok? ----4
{}
void test(int (*arr)[5])//ok? ----5
{}
void test(int **arr)//ok? ----6
{}
int main()
{int arr[3][5]={0};test(arr);
}
二维数组传参经验总结:
- 二维数组传参时可以写成形参二维数组的形式,行可以不写大小,但是列一定要写大小。
- 在传参时传入的是数组指针类型,所以不能用一级指针接收,也不能用指针数组、二级指针来接收,这样是类型上就不对的了
综上,2,4,6是错误的传参形式。
一级指针传参
Q:当函数的参数为一级指针时,函数能接收什么参数?
A:可以传入一个地址,或数组名,或直接传入一个一级指针。
二级指针传参
Q:当函数的参数为二级指针时,函数能接收什么参数?
A:可以传入一级指针的地址、二级指针、指针数组的数组名。
函数指针
函数不同于数组,函数名与在函数名前加上&本质上是没有区别的,下面是函数指针的一些使用:
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
void Fun(char x)
{;
}
int main()
{//Add与&Add本质上没有区别,都表示为同一个地址printf("%p\n", Add);printf("%p\n", &Add);//函数指针的创建举例int (*p)(int, int) = Add;int (*pa)(int, int) = &Add;void (*ppa)(char) = Fun;//函数指针的调用也同函数名一样,可以直接用名或者在前面加上解引用符printf("%p\n", p);printf("%p\n", *p);//函数的调用printf("%d\n", Add(1, 2));printf("%d\n", (&Add)(1, 2));//这里特别注意,要将&Add用小括号括起来,否则Add就会先与后面的(1,2)结合,从而无法调用函数。printf("%d\n", p(1, 2));printf("%d\n", (*p)(1, 2));//*p也是先要用小括号括起来,否则会与后面的(1,2)结合,从而无法调用函数得到想得到的结果。return 0;
}
特别注意:以上面代码为例,若要以&Add或者*p这种形式来使用,要先用小括号括起来,否则Add/p就会先与后面的(1,2)结合,从而无法调用函数。
在学习函数指针时,又偶然发现了一道很经典,非常,特别,诡异的题目:
//请分析下面这段代码:
(*(void(*)())0)();
??????????????????????????????????????????????????????????????????????????????????????
在刚看到这段代码时我的心情如上
C语言中多种指针相关类型详解相关推荐
- c语言二级指针有什么作用,C语言中二级指针的实例详解
C语言中二级指针的实例详解 C语言中二级指针的实例详解 用图说明 示例代码: #include int main(int argc, const char * argv[]) { // int a = ...
- c语言结构体成员变量私有化,C语言中结构体变量私有化详解
C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...
- C语言中三个数比较大小详解——三种方法
C语言中三个数比较大小详解--三种方法 方法一:if-else法 方法二:函数法 方法三:三目运算符法 C语言中比较三个数的大小有很多方法,以下是我总结的三种方法: 首先我定义 int a = 1 ...
- c语言自定义color,forecolor c语言中的颜色设置语句详解
backcolor与forecolor的区别 backcolor:用来设置图像的背景颜色,也用来设置文档.表格.图像等的背景颜色. forecolor:用来设置图像的前景颜色,也用来设置文档.表格.图 ...
- c语言输入循环语句,C语言中输入输出和循环语句详解.ppt
C语言中输入输出和循环语句详解 C语言的输入输和循环分支语句详解 本章主要向大家介绍下C语言的输入和输出功能以及循环分支语句的使用 第4章 顺序结构程序设计 3.1 C语言语句 3.2 赋值语句 3. ...
- C语言(函数指针数组)详解
要了解函数指针数组,可以从三个角度来分析.所谓函数指针数组,从字面意思上来解析,函数指针数组的组成有三个点,函数,指针,数组.首先我们知道,函数指针数组,是一个数组,数组的每个元素是函数指针,也就是一 ...
- c语言实现结构体变量private,C语言中结构体变量私有化详解
背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate ...
- C语言中的数据类型及其转换详解
http://www.cnblogs.com/jpcflyer/archive/2012/02/16/2353447.html 1. C语言中的数据类型 C语言中的类型按其组成可以分为简单类型和构造类 ...
- 【明解C语言】之指针初阶详解
目录 一.指针是什么 二.指针和指针类型 1. 指针+-整数 2. 指针的解引用 3.练习 三.野指针 1.野指针成因 2.规避野指针的有效方法 四.指针运算 1.指针+-整数 2.指针-指针 3.指 ...
最新文章
- 电脑温度测试软件_网购电脑够便宜?坑连着坑真的不好躲
- oracle10g- emctl start dbconsole 启动问题
- 关于vs中代码生成的运行库
- SQL Server 无法生成 FRunCM 线程。请查看 SQL Server 错误日志和 Windows 事件日志(转)...
- 浅谈PPM (Project Portfolio Management)
- css两张图片怎么合在一起_web前端入门到实战:纯CSS实现两个球相交的粘粘效果...
- Oracle01877,Cognos错误:RQP-DEF-0177 执行操作“sqlOpenResult”(状态为“-28”)时出错...
- Spring3核心技术之AOP配置【转】
- Struts2中过滤器和拦截器的区别
- Excel将数据内容导出为数据库DBF文件的操作
- 手机图片如何转化为Word文档?简单几步轻松转换
- 高防虚拟主机怎么选?
- Gradle 配置阿里云代理 https,maven central 中央仓库,google,gradle plugin,jcenter
- android recovery分区内刷镜像,Android手机Recovery模式取证方法研究.pdf
- 室内地图导航系统基础功能与衍生服务详解
- StoneDB 为何敢称业界唯一开源的 MySQL 原生 HTAP 数据库
- ROS noetic gazebo11车轮不显示的问题
- roboware-studio在ubuntu18.04出现像素干扰点解决
- Cannot spawn .husky/pre-commit: No such file or directory
- 华为mate7android5.1,『独家首发』基于最新Android5.1版本 Mate7 EMUI3.1轻度体验报告...