声明返回数组指针的函数

时间:2014.05.18

地点:基地

------------------------------------------------------------------------

一、基本知识

  常识:数组不能被拷贝,函数不能返回数组,只能返回数组的指针或者引用。

typedet int arr[10]; //arr是类型别名,表示的类型含有10个整数的数组
上述语句等效于

using arr=int[10]

在来复习几个基础知识

int arr[10];   //arr是一个含有10个整数的数组
int *p1[10];  //p1和[ ]的结合度要高,所以p1首先是一个10个大小的数组,即这里的p是一个数组名,其次是与*结合,表数组中每个元素都是整型指针
int (*p)[10]=&arr;  //由于括号p首先与*结合,即p是一个指针,然后才与[ ]结合,说明p指针指向大小为10的一个数组,且p指针初始化,p是一个数组指针

------------------------------------------------------------------------

二、声明返回数组的指针

  联系一般的赋值语句:

int a=b;
int a=fun(c);
即发生函数调用时这里的func(c)和b等同的地位,于是,当函数返回数组指针时我们也要等同于 int (*p)[10]的形式,按照这种法则,返回函数指针的函数形式如下:

Type(*function(parameter_list))[dimension]
和函数指针 int(*p)[10]对应,(*function(parameter_list))是相当于(*int p),后面在跟上返回数组指针所指向的数组的维度。
一个例子:

int (*func(int i))[10];
func(int i)  意味着调用func函数时需要一个int类型的实参

(*func(int)) 意味着对函数调用的结果是一个指针

(*func(int i))[10] 意味着对函数调用结果的指针是一个指向数组,数组大小为10

int (*func(int))[10] 意味着对函数调用结果的指针指向的数组中,数组元素都是整型的。

但正如前面所说,
若果我们使用类型别名,声明一个返回数组指针的函数的函数就看起来要优雅多了

using arrT=int[10]; //arr是大小为10的数组的一个别名,即相当于把int[10]看成是一种类型,该类型是一个整型数组,大小为10
有了这,现在声明一个返回数组指针的函数时就是声明一个返回这样类型的指针了,于是很优雅的如下:

arrT* func(int i);

------------------------------------------------------------------------

三、使用尾置返回类型

  在上面方式中,个人非常喜欢用using语句,它非常直观简明。然而在声明返回类型时,我们还有一种更简洁的办法,那就是使用尾置返回类型。任何函数的定义都能使用尾置返回,它在形参列表后以一个 -> 符号开头,为表示函数真正的返回类型在形参列表之后,我们在最前放置一个auto,比如:

auto func(int i)->int(*)[10];  //func接受一个int类型的实参,返回一个指针,指针指向10个整数的数组
于是现在就可以清楚地看到func函数返回的是一个指针,该指针指向10个整数的数组。

------------------------------------------------------------------------

四、使用decltype

  若果知道函数返回的指针指向哪个数组还可以使用decltype关键字声明返回类型,比如一个典型的例子:

#include<iostream>
int odd[] = { 1, 3, 5, 7, 9 };
int even[] = { 0, 2, 4, 6, 8 };
decltype(odd)* func(int i)
{
	return (i & 1) ? &odd : &even;
}
int main()
{
	
	std::cout << (*func(1))[2]<< std::endl;
	std::cout << (*func(2))[2] << std::endl;
}
deltype的作用是负责推导出表达式的类型,在这里是推导出odd的类型是一个大小为5的数组,但只是数组这种类型,要让成为一个指向这个类型的的指针,和正常一样加上*即可。







<think>好的,用户想了解C语言中数组指针函数的使用方法及相关概念。首先,我需要整理这三个部分的基础知识,确保覆盖它们的定义、声明、初始化以及相互关系。 先从数组开始。数组是存储相同类型元素的集合,需要说明一维和多维数组声明和初始化方式,比如int arr[5]和int matrix[3][3]。然后,举一个遍历数组的例子,帮助用户理解如何操作数组元素。 接下来是指针指针存储内存地址,声明方式如int *ptr。要解释指针的初始化,比如指向变量或数组,强调指针的算术运算和通过指针访问值。这里需要区分指针数组数组指针,比如int *ptrArr[5]和int (*arrayPtr)[5],这部分容易混淆,需详细说明。 然后是函数部分。函数的定义和调用是基础,但重点在于函数指针的结合,比如函数指针。需要说明如何声明函数指针,例如int (*funcPtr)(int, int),并演示如何通过指针调用函数。此外,函数指针数组也是一个重要概念,可以举例说明其用法,比如回调函数或状态机。 接下来需要整合数组指针函数之间的关系。例如,如何将数组作为参数传递给函数,实际上传递的是指针,因此函数内对数组的修改会影响原数组。这里可以举一个计算数组平均值的例子。同时,函数返回指针的情况需要注意合法性,避免返回局部变量的地址。 关于指针数组数组指针的区别,用户提供的引用中已经提到,需要进一步澄清。指针数组是元素为指针数组,而数组指针是指向整个数组指针,步长以整个数组为单位。这部分可以通过代码示例来说明,比如指针数组用于字符串数组数组指针用于二维数组的行指针函数指针的应用场景,如回调函数,可以举例qsort函数的使用,展示如何通过函数指针实现自定义排序。函数指针数组适用于根据索引调用不同函数的情况,比如菜单驱动系统。 用户可能存在的疑问点包括指针数组名的区别,数组名在大多数情况下被视为指针,但不能被重新赋值。此外,动态内存分配涉及指针的使用,如malloc和free,但用户的问题中没有明确提到,可能需要简要提及。 最后,生成的相关问题需要覆盖常见疑惑点,比如指针数组的区别、函数指针的应用、多维数组指针的关系,以及如何避免指针使用中的常见错误。确保问题能够引导用户深入理解每个概念及其实际应用。 需要检查引用文献,确保引用内容准确。引用[1]提到函数指针数组,引用[2]解释数组指针,这些在回答中需要正确标注。同时,确保示例代码符合C语法,避免错误,比如函数指针声明和调用。 总结回答结构:分三个主要部分讲解数组指针函数,再讨论它们的结合应用,最后给出相关问题。每个部分包含定义、声明、示例代码和注意事项,确保逻辑清晰,便于用户逐步理解。</think>### 数组指针函数在C语言中的使用方法 #### 一、数组 1. **定义与初始化** - 数组是存储**相同数据类型**元素的内存块,声明格式为:`数据类型 数组名[长度]`。 - 示例: ```c int arr[5] = {1, 2, 3}; // 一维数组,未初始化的元素默认为0 int matrix[3][3]; // 二维数组 ``` 2. **数组指针的关系** - 数组名本质是**指向数组首元素的指针常量**,例如`arr`等价于`&arr[0]`。 - 通过指针访问数组元素: ```c int *ptr = arr; printf("%d", *(ptr + 2)); // 输出第三个元素 ``` #### 二、指针 1. **指针基础** - 指针存储变量的内存地址,声明格式为:`数据类型 *指针名`。 - 示例: ```c int a = 10; int *p = &a; // p指向a的地址 printf("%d", *p); // 输出10 ``` 2. **指针数组 vs 数组指针** - **指针数组**:存储多个指针数组,如`int *ptrArr[5]`。 ```c char *strs[] = {"Hello", "World"}; // 字符串数组指针数组) ``` - **数组指针**:指向整个数组指针,如`int (*arrayPtr)[5]`。 ```c int arr2D[2][3] = {{1,2,3}, {4,5,6}}; int (*ptr)[3] = arr2D; // 指向二维数组的行指针 ``` #### 三、函数 1. **函数定义与调用** - 函数通过参数和返回值操作数据,例如: ```c int add(int a, int b) { return a + b; } ``` 2. **函数指针** - 函数指针指向函数代码段,声明格式:`返回值类型 (*指针名)(参数列表)`。 ```c int (*funcPtr)(int, int) = add; // 指向add函数 printf("%d", funcPtr(3, 5)); // 输出8 ``` 3. **函数指针数组** - 存储多个函数指针数组,用于动态调用函数[^1]。 ```c int (*operations[4])(int, int) = {add, subtract, multiply, divide}; operations[0](3,5); // 调用add函数 ``` #### 四、三者的结合应用 1. **数组作为函数参数** - 传递数组时实际传递的是指针,例如: ```c void printArray(int *arr, int size) { for (int i=0; i<size; i++) printf("%d ", arr[i]); } ``` 2. **指针函数函数指针** - **指针函数**:返回指针函数,需注意返回地址的有效性。 ```c int* createArray(int size) { int *arr = (int*)malloc(size * sizeof(int)); return arr; // 返回动态内存地址 } ``` #### 五、关键区别与注意事项 1. **数组名 vs 指针** - 数组名是常量指针,不可重新赋值(如`arr = new_address`非法)。 - 指针变量可修改指向(如`p = &b`合法)。 2. **多维数组指针** - 二维数组名是**行指针**,`arr2D[i][j]`等价于`*(*(arr2D + i) + j)`[^2]。 3. **动态内存管理** - 使用`malloc`和`free`避免内存泄漏: ```c int *dynamicArr = (int*)malloc(5 * sizeof(int)); free(dynamicArr); // 释放内存 ``` --- ### 相关问题 1. 指针数组名在内存访问时有何异同? 2. 如何通过函数指针实现回调机制? 3. 多维数组如何通过指针进行高效遍历? 4. 指针使用中常见的错误(如野指针、内存泄漏)如何避免? --- [^1]: 函数指针数组允许通过索引调用不同函数,常用于状态机或策略模式。 : 数组指针指向整个数组,步长由数组大小决定,例如`int (*)[5]`的步长为`5*sizeof(int)`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值