C语言之指针高级--指针操作二维整型、字符型数组、函数指针

指针操作二维整型数组

回顾:在C语言中并不存在真正的二维数组,二维数组的本质 是一维数组的一维数组 ,比如定义一个二维数组 int a23,本质上是 int 3 a2,表示定义了一个数组类型(具体类型是int 3)的一维数组a2,在学习指针操作二维数组时,要从其本质出发,否则很可能被绕晕。二维数组 也 符合数组的特点 ,即连续性,有序性,单一性 。

指针定义的语法是

基类型 * 变量名

那么应该需要确定一个基类型是什么的指针,来指向二维数组呢?

如果对二维数组本质比较清楚,那么a23中,a0(即所谓的"第一行")的类型是int 3这种数组类型,由此可以推断 &a0 对应就是 int 3*,只不过C语言中不允许这种写法,所以正确的写法是int (*) 3,即定义了一个数组类型的指针,就是数组指针。所以我们就可以定义一个这样类型的指针:

int (* p)3 = a // 表示p指向了二维数组a,p的基类型相当于int 3

*p <=> a0 //相当于是内部的一维数祖名

(*p)0 <=> *(*p+0) <=> **p // 都表示a00;

*(*(p+1)+1) <=> a11

*(*(p+i)+j) <=> aij

若a是二维数组,则ai 代表一维数组名,它只是一个地址,并不代表某一个元素的值,所以a 、a+i、ai、*(a+i)、*(a+i)+j、ai + j都是地址;而*(ai + j)和 *(* (a+i) + j) 是二维数组元素ai j的值。

注意:

二维数组的操作

从二维数组的本质 进行的 ,直接的访问操作也是 一维一维的展开 。

以下是简单使用实例,实现二维数组打印

复制代码
#include <stdio.h>

int main(void)
{

	int a[2][3] = {1,2,3,4,5,6};

	int (*p)[3] = a;
	
	int i = 0;
	int j = 0;
	for (i = 0;i < 2; ++i)
	{
		for (j = 0; j < 3; ++j)
		{
			//相当于printf("%d ",a[i][j]);
			printf("%d ",*(*(p+i) + j));
		}
		putchar('\n');
	}
	
	return 0;
}

指针操作二维字符型数组

二维字符型数组主要用来处理字符串,所以指针操作二维字符型数组,就是操作字符串。定义指针变量类似二维整型数组。

但是有两种方式可以给值:

方式1

char s = {"hello", "world"};

char (*p) 10 = s; //表示p指向二维数组s

因为二维字符型数组主要操作字符串,所以我们是取一整个字符来进行操作的,所以用指针访问时,直接 *(p+i)就可以取到字符串,这是区别于二维字符型数组的地方。

方式2

在一维字符型数组中,我们可以 char * p = "hello",表示定义了一个指针变量,直接指向了字符串,就是p存了字符串常量区中放hello的地址。那么对于多个存放字符串的地址,我们可以:

char * p1 = "hello";

char * p2 = "world";

char * p3 = "China";

......

C语言中用数组来批量处理数据,所以定义了一个数组:

char * p3 = {"hello", "world","China"};

因为要存放地址这种类型,所以基类型是char *,也就是指针类型,数组p里面存放的是指针类型的变量----地址。

对于p3这个数组来说,里面存放的是各个字符串的地址,也就是存放着地址数据的数组,就是**指针数组,**注意区别于数组指针。

所以如果要定义一个指针来指向这个数组,可以写成:

char * * q = p; //q是二级指针

char * 代表基类型是指针类型

* 代表定义了一个指针类型的变量q,只是一个声明,无其它含义。

应用:

int main (int argc, const char * argv )

在C语言和C++语言中,main 函数是程序的入口点,它可以接受两个参数: argc 和 argv\[\] 。这两个参数允许程序接收从命令行传递给程序的参数。

  1. **argc**:这是一个整型变量,表示命令行中传递给程序的参数个数。它包括程序本身的名称,所以至少为1。例如,如果在命令行中运行 program arg1 arg2,argc 的值将是3。

  2. **argv\[\]**:这是一个字符指针数组,每个元素指向一个以null结尾的字符串。argv0是程序本身的名称,argv1是第一个参数,argv2`是第二个参数,依此类推。argv数组的最后一个元素是一个空指针(即NULL或`nullptr),表示参数列表的结束。

用法示例:

假设有一个C程序,其main函数定义如下:

int main(int argc, char *argv\[\]) {

// 程序代码

return 0;

}

如果在命令行中运行这个程序并传递参数,如下

./myprogram arg1 arg2 arg3

那么在程序中,argc的值将是4,argv数组将包含以下元素:

argv0 -> "./myprogram"

argv1 -> "arg1"

argv2 -> "arg2"

argv3 -> "arg3"

argv4 -> NULL

在程序中,可以使用这些参数来执行不同的操作,例如

int main(int argc, char *argv\[\]) {

if (argc > 1) {

printf("Number of arguments: %d\n", argc - 1);

for (int i = 1; i < argc; i++) {

printf("Argument %d: %s\n", i, argvi);

}

}

return 0;

}

这个程序将打印出除了程序名称之外的参数个数,以及每个参数的值。

指针 + 函数

通过指针 的方式 来调用函数

函数名 --- 代表函数的入口地址

int add(int a,int b) // 求和函数

// 函数名 - 代表函数的入口地址

// 函数名对应的数据类型

// int (int a,int b) //函数类型

// 代表一类函数

// 返回值为int型

// 带有两个int型的形参变量

说明:

1.可以定义一个函数类型的指针变量

来保存函数的入口地址

int (*p)(int, int ) = add

2.有了这个指针变量

通过指针变量 进行函数调用

int ret = p(1,2)

一般用于实现函数回调(callback)

回调函数 --- 通过函数指针调用函数 就是回调。c语言中,使用了函数指针实现回调。

以下是回调的简单实例:

复制代码
#include <stdio.h>

int add(int a,int b)
{
	return a + b;
}

int sub(int a,int b)
{
	return a - b;
}
int mul(int a,int b)
{
	return a * b;
}
int div(int a,int b)
{
	return a / b;
}


void processData(int a,int b,int(*p)(int,int))
{
	printf("result: %d\n",p(a,b));
}

int main(int argc, const char *argv[])
{

	processData(1,2,add);
	processData(1,2,sub);
	processData(1,2,mul);
	processData(1,2,div);
	
	return 0;
}
相关推荐
丘山望岳14 小时前
藤萝垂序——二叉搜索树
开发语言·数据结构·c++
惊鸿一博15 小时前
统计_滚动标准差:局部波动性衡量
开发语言·python
这个DBA有点耶15 小时前
数据库管理工具+开发工具的融合:AI如何重塑DBA工作流?
开发语言·数据库·人工智能·sql·云计算·dba
lynnlovemin15 小时前
【信息学竞赛专题】滑动窗口(尺取法)超全详解|C++模板+经典例题+避坑指南
开发语言·c++·算法·滑动窗口·信息学竞赛
社交怪人15 小时前
【等差数列】信息学奥赛一本通C语言解法(题号1035)
c语言
不会C语言的男孩15 小时前
VS Code 中搭建 C/C++ 开发环境(MSYS2 编译器)
c语言·c++
我叫张小白。15 小时前
Redis常用数据结构与命令详解
数据结构·数据库·redis
wjs202415 小时前
JavaScript 类型转换
开发语言
似水এ᭄往昔15 小时前
【Qt】--Qt概述
开发语言·c++·qt
星秀日16 小时前
rust学习入门
开发语言·学习·rust