c语言指针进阶(一)

news/2024/7/8 10:14:41

        大家好,我是c语言boom成家宝。今天为大家分享的是c语言中很重要的一个知识点------指针的深入讲解。 

目录

指针     

指针数组

数组指针

·函数指针


什么是指针?

        首先,指针的本质是一个地址,指针在32位机器上的大小是4个字节,在64位机器上的大小是8个字节。指针也有各种类型,其格式如下:

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

           指针的类型可以决定指针解引用时能访问多少个字节的内容,例如int类型我们解引用以后可以调4个字节,char类型1个字节。知晓这个原理以后我们不妨来思考一下下面这几个例子的答案是多少

	  int a[] = { 1,2,3,4 };
	  printf("%d\n", sizeof(a));
      printf("%d\n", sizeof(a+0));
      printf("%d\n", sizeof(*a));
      printf("%d\n", sizeof(a+1));
      printf("%d\n", sizeof(a[1]));
      printf("%d\n", sizeof(&a));
      printf("%d\n", sizeof(*&a));
	  printf("%d\n", sizeof(&a+1));
	  printf("%d\n", sizeof(&a[0]));
	  printf("%d\n", sizeof(&a[0]+1));

                正确答案如下:  内容代码参考博主:初阳785

	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16 sizeof(数组名)-计算的是数组总大小-单位是字节
	printf("%d\n", sizeof(a+0));//4/8 这里a表示表示首元素地址 a+0 还是表示首元素地址 地址的大小就是4/8个字节
	printf("%d\n", sizeof(*a));//4 这里的a表示首元素地址 *a 解引用操作拿到第一个元素 数组的每个元素的类型是int int的大小是4个字节
	printf("%d\n", sizeof(a+1));//4/8 a表示首元素地址 a+1 表示第二个元素的地址 归根到底是一个地址 地址的大小就是4/8个字节
	printf("%d\n", sizeof(a[1]));//4 //计算第二个元素的大小。
	printf("%d\n", sizeof(&a));//4/8 &a表示整个元素的地址 但是整个元素的地址 还是个地址 而地址的大小就是4/8个字节
	printf("%d\n", sizeof(*&a));//16 &a表示整个数组的地址 *&a 解引用就拿到整个数组的元素 4*4=16
	printf("%d\n", sizeof(&a+1));//4/8 &a是数组的地址,&a+1虽然地址跳过整个数组,但还是地址,所以是4/8个字节
	printf("%d\n", sizeof(&a[0]));//4/8 第一个元素的地址
	printf("%d\n", sizeof(&a[0]+1));//4/8 第二个元素的地址

什么是指针数组?

        指针数组缩句就是数组,例如整型数组就是存放整型的数组,字符串数组就是存放字符串的数组,那么指针数组就是存放指针的数组。

        接下来我们可以使用指针数组来模拟二维数组的实现。代码如下:

int main() {
	int arr1[] = { 1,2,3 };
	int arr2[] = { 4,5,6 };
	int arr3[] = { 7,8,9 };
	int* arr[] = { arr1,arr2,arr3 };//数组指针的创建,类型是int*
	//遍历数组指针内容并打印
	int i =0 ;
	for (i = 0; i < 3; i++) {
		int j = 0;
		for (j = 0; j < 3; j++) {
			printf("%d ", arr[i][j]);
		}
	}
	return 0;
}

 什么是数组指针?

        数组指针归根结底还是指针,例如整型指针就是存放整型变量地址的指针变量,字符型指针就是存放字符型变量地址的指针,那么数组指针就是存放数组地址的指针变量。

        这两行代码大家认为哪一个是数组指针呢?答案是第二个。第一个是指向int*的一个指针数组,第二个有括号括起来改变优先级的才是数组指针。以下是数组指针的一个简单用法实例。

int main() {
	int arr[5] = { 1,2,3,4,5 };

	//数组内容存放在数组指针中

	int(*p)[5] = &arr;
	return 0;
}

        那数组指针到底在什么场景下使用才方便一些呢?博主给出其中一个答案就是二维数组里面。 代码如下

void Print(int arr[3][5], int row, int col) {
	int i = 0;
	for (i = 0; i < 3; i++) {
		int j = 0;
		for (j = 0; j < 5; j++) {
			printf("%d ", arr[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);//这里Print函数是自己创建的,不是库函数printf
	return 0;
}

        这是我们平熟悉的常用的遍历并打印二维数组的方法,那我们学习了数组指针过后又可以怎么让形参是指针去遍历二维数组呢?首先二维数组的数组名也是数组名,也表示首元素的地址。那二维数组可以理解为由若干个一维数组组成的数组,所以二维数组首元素的地址也就是第一个一维数组的地址,所以我们实参部分传过去的是一维数组的地址,那我们形参部分就应该用一个数组指针来接收,代码如下:

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拿到的就是那一行一维数组的地址,*(p+i)解引用过后就是一行数组的数据
			                             //*(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);//这里Print函数是自己创建的,不是库函数printf
	return 0;
}

编译结果如图:

        很多小伙伴看到这里或许会觉得很别扭,觉得我不如使用第一种常规的。这是因为接触的少了,看的代码看得少了所以会觉得很奇怪。这里博主强烈建议大家都去使用第二种方法,因为你自己在使用第一种方法的时候其实编译器在处理过程中它自己会转变成第二种来处理,所以直接写成这样在以后的编译中运行效率会更快,占用内存更少。

·什么是函数指针?

        数组指针是指向数组的指针,函数指针当然就是指向函数的指针了。小知识:函数名表示为函数的地址,&函数名也表示函数的地址。如下图

        那函数指针的形式该怎么写呢?举两个例子:如果函数形式是int add(int x,int y),那么函数指针就可以写成:int (*add)(int,int)=&add.    如果函数形式是 void test(char* pc,int arr[10]),那么函数指针可以写成 void (*p)(char* ,int [10])=&test,或者void (*p)(char* ,int *)=&test。函数指针第一个类型表示返回值的类型,然后(*p),然后(参数类型)。那么函数指针可以怎么使用呢,下面代码是一个简单的使用案例

int add(int x, int y) {
	return x + y;
}


int main() {
	int (*p)(int, int)=&add;//函数指针定义
	int r = add(3, 5);
	printf("%d\n", r);
//正常使用add函数进行计算

	int m = (*p)(3, 5);

//使用指针调用add函数

	printf("%d", m);

	return 0;
}

 


http://www.niftyadmin.cn/n/3652525.html

相关文章

高阶SQL语句(排序,分组,限制,别名,通配符,子查询,视图,null值)

文章目录准备工作MySQL高阶语句常用查询按关键字排序1、单字段排序2、多字段排序3、或/且&#xff08;or/and&#xff09;4、查询不重复记录对结果进行分组限制结果条目设置别名AS作为连接语句通配符子查询定义、示例in的用法2、子查询-别名as子查询-exists视图示例&#xff08…

高阶SQL语句2(正则表达式,运算符,比较运算,逻辑运算符,位运算,连接查询)

文章目录正则表达式regexp 操作符所支持的匹配模式如下&#xff1a;运算符算术运算比较运算符常用比较运算符&#xff08;比较对象&#xff1a;数字&#xff0c;字符&#xff09;等于 &#xff08;&#xff09;不等于&#xff08;!或<>&#xff09;大于&#xff0c;小于两…

[转]ASCII 代码表(0-255)

ASCII 代码表II Ascii 代码表 Ascii 0 {Nulo, Sem Som} Ascii 1 Ascii 2 Ascii 3 Ascii 4 Ascii 5 Ascii 6 Ascii 7 Ascii 8 {BackSpace} Ascii 9 {Tab} Ascii 10 Ascii 11 Ascii 12 Ascii 13 {Enter} Ascii 14 Ascii 15 Ascii 16 {Shift} Ascii 17 {CTRL} Ascii 18 {ALT} Asci…

[转]Sqlite中文排序研究

Sqlite中文排序研究转载时请注明出处&#xff1a;http://blog.csdn.net/absurdSqlite是一个用C语言实现的小型SQL数据库引擎。它体积小巧但功能强大&#xff0c;对硬件资源要求很低而且性能表现卓越&#xff0c;非常适合于嵌入式应用环境。最近发现sqlite并不支持中文(拼音/笔画…

高阶SQL3(数据库,数学,聚合,字符串,时间,储蓄过程)

文章目录数据库函数数学函数聚合函数字符串函数trim() 返回去除指定格式的值日期时间函数储蓄过程概述简介优点创建存储过程不带参数的创建参数带参数的存储过程其他命令数据库函数 MySQL 数据库函数提供了能够实现各种功能的方法&#xff0c;使我们在查询记录时能够更高效的输…

[转]数据库中的多级结构存储(实例)

来自&#xff1a;http://blog.sina.com.cn/u/467cbd19010000hs在项目开发中&#xff0c;经常会碰到存储多级数据结构&#xff08;树状&#xff09;的问题。经过查找资料&#xff0c;总结出层次结构存储的两种设计方法&#xff1a;1&#xff1a;邻接表模式&#xff08;adjacency…

[转]Plucene介绍

Plucene介绍作者&#xff1a;chiesa 最后更新&#xff1a;2005/9/25概述Lucene不是一个完整的全文索引应用&#xff0c;而是是一个用Java写的全文索引引擎工具包&#xff0c;它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。Plucene基于java lucene项目创建。Pl…

MySQL MHA高可用集群部署和故障模拟

文章目录MySQL MHA传统的MySQL主从架构存在的问题MHA概述MHA的组成MHA 的特点搭建MySQL MHA实验思路实验环境、安装包关闭服务器防火墙和安全机制修改三台MySQL服务器的主配置文件配置MySQL&#xff08;一主两从&#xff09;主从复制验证安装MHA软件在所有服务器上配置无密码认…