目录

指针数组

数组指针

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语言中多种指针相关类型详解相关推荐

  1. c语言二级指针有什么作用,C语言中二级指针的实例详解

    C语言中二级指针的实例详解 C语言中二级指针的实例详解 用图说明 示例代码: #include int main(int argc, const char * argv[]) { // int a = ...

  2. c语言结构体成员变量私有化,C语言中结构体变量私有化详解

    C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...

  3. C语言中三个数比较大小详解——三种方法

    ​ C语言中三个数比较大小详解--三种方法 方法一:if-else法 方法二:函数法 方法三:三目运算符法 C语言中比较三个数的大小有很多方法,以下是我总结的三种方法: 首先我定义 int a = 1 ...

  4. c语言自定义color,forecolor c语言中的颜色设置语句详解

    backcolor与forecolor的区别 backcolor:用来设置图像的背景颜色,也用来设置文档.表格.图像等的背景颜色. forecolor:用来设置图像的前景颜色,也用来设置文档.表格.图 ...

  5. c语言输入循环语句,C语言中输入输出和循环语句详解.ppt

    C语言中输入输出和循环语句详解 C语言的输入输和循环分支语句详解 本章主要向大家介绍下C语言的输入和输出功能以及循环分支语句的使用 第4章 顺序结构程序设计 3.1 C语言语句 3.2 赋值语句 3. ...

  6. C语言(函数指针数组)详解

    要了解函数指针数组,可以从三个角度来分析.所谓函数指针数组,从字面意思上来解析,函数指针数组的组成有三个点,函数,指针,数组.首先我们知道,函数指针数组,是一个数组,数组的每个元素是函数指针,也就是一 ...

  7. c语言实现结构体变量private,C语言中结构体变量私有化详解

    背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate ...

  8. C语言中的数据类型及其转换详解

    http://www.cnblogs.com/jpcflyer/archive/2012/02/16/2353447.html 1. C语言中的数据类型 C语言中的类型按其组成可以分为简单类型和构造类 ...

  9. 【明解C语言】之指针初阶详解

    目录 一.指针是什么 二.指针和指针类型 1. 指针+-整数 2. 指针的解引用 3.练习 三.野指针 1.野指针成因 2.规避野指针的有效方法 四.指针运算 1.指针+-整数 2.指针-指针 3.指 ...

最新文章

  1. 电脑温度测试软件_网购电脑够便宜?坑连着坑真的不好躲
  2. oracle10g- emctl start dbconsole 启动问题
  3. 关于vs中代码生成的运行库
  4. SQL Server 无法生成 FRunCM 线程。请查看 SQL Server 错误日志和 Windows 事件日志(转)...
  5. 浅谈PPM (Project Portfolio Management)
  6. css两张图片怎么合在一起_web前端入门到实战:纯CSS实现两个球相交的粘粘效果...
  7. Oracle01877,Cognos错误:RQP-DEF-0177 执行操作“sqlOpenResult”(状态为“-28”)时出错...
  8. Spring3核心技术之AOP配置【转】
  9. Struts2中过滤器和拦截器的区别
  10. Excel将数据内容导出为数据库DBF文件的操作
  11. 手机图片如何转化为Word文档?简单几步轻松转换
  12. 高防虚拟主机怎么选?
  13. Gradle 配置阿里云代理 https,maven central 中央仓库,google,gradle plugin,jcenter
  14. android recovery分区内刷镜像,Android手机Recovery模式取证方法研究.pdf
  15. 室内地图导航系统基础功能与衍生服务详解
  16. StoneDB 为何敢称业界唯一开源的 MySQL 原生 HTAP 数据库
  17. ROS noetic gazebo11车轮不显示的问题
  18. roboware-studio在ubuntu18.04出现像素干扰点解决
  19. Cannot spawn .husky/pre-commit: No such file or directory
  20. 华为mate7android5.1,『独家首发』基于最新Android5.1版本 Mate7 EMUI3.1轻度体验报告...

热门文章

  1. 这是我做的皮肤!就叫他sakebowUI了!
  2. 养生理疗馆有哪些服务项目
  3. 开源高仿印象笔记的iOS应用——朝夕笔记(Oncenote)
  4. DIV或Divide命令 等分对象
  5. uni-app实战之社区交友APP(7)消息页开发
  6. Android设置壁纸
  7. 微信小程序关闭苹果手机的下拉刷新
  8. 新支点操作系统linux内核版本,新支点操作系统入围
  9. ★★★同时支持iexplorer和firefox的javascript复制拷贝信息到剪贴板方法
  10. 在家创业系统常见问题-问答