向C函数中传递指向二维数组的指针参数
先来回顾一下一维数组,一维数组的数组名即为指向该数组的指针,该指针值保存了数组存放在内存中的一块连续区域的起始地址;数组的下标表示了这片内存区域的某存储区相对于起始地址的偏移量。简单来讲就是:指向一维数组的指针,指向数据存放区域的起始位置。事实上,计算机系统的多维数组其实最终还是以一维数组的形式实现的。
就N x M的二维数组来讲,设其数组名为array
指针array指向一个数组,该数组存放的是一系列指针,这些指针分别指向相应的一维数组,而这些数组中存放的才是我们的数据。
array -> [一维数组指针1] -> [一维数组,M长]
[一维数组指针2] -> [ 一维数组,M长]
[一维数组指针N] -> [ 一维数组,M长]
由此array[i]是第i个指针变量地址,array[i][j]则表示相对于第i个指针变量偏移j*sizeof(数组类型)。
系统通过这种机制访问了该二维数组的第i行,第j列的内容。
有上述可知,指向二维数组的指针其实是指向“指针变量地址”的指针变量。所以在声明指向二维数组的指针时,用int ** array的形式。
有以下两种方式来对二维数组分配内存:
方法一
#include <stdlib.h>
//必须包含该头文件,里面定义了malloc的实现
int ** array = malloc( N * sizeof(int *) );
for (int k=0;k<N;k++)
array[k] = malloc( M * sizeof(int) );
int** array = (int**)malloc(N);
for (int i = 0;i < N;i++)
array[i] = (int*)malloc(M);
int **array = new int*[N];
for (int i = 0;i < N;i++)
array[i] = new int[M];
方法二
#include <stdlib.h>
int ** array = malloc( N * sizeof(int *) );
array[0] = malloc( M * sizeof(int) );
for (int k=1;k<N;k++)
array[k] = array[0]+M*k;
上述两种方法的区别在于:前者在内存中分配的区域有可能
是不连续的;而后者则在内存中的一片连续区域为该数组分配空间。
我们还可以通过一维数组模拟二维数组。在这中间要进行下
标转换。如对于模拟的NxM数组,访问其i第行,第j列元素时,一维数组中对应的位置是i*M+j。当然为了更简捷,我们可以把这个数组下标转换过程定义为一个宏,交由编译系统来处理。
#define Arr2 ( array_name, row,col )
array_name[row*M+col]
定义该宏后,访问Arr2( array, i, j)等价于访问array[i*M+j]
方法三
可以接收不同类型数据,强制类型转换
#include <QtCore/QCoreApplication>
#include "opencv2\opencv.hpp"
void print(void **tab,int rows,int cols)
{
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
cout<<*((float *)tab+i*cols+j)<<" ";
}
cout<<endl;
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
float ta[2][3]={{1.0,2.0,3.0},{4.0,5.0,6.0}};
cout<<"ta: "<<endl;
print((void **)ta,2,3);//打印
return a.exec();
}
函数返回数组
C不支持在函数外返回局部变量的地址,除非定义局部变量为static变量
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int * function () {
static int r[10];
//设置种子
srand((unsigned)time(NULL));
for (int i = 0;i < 10;i++)
r[i] = rand();
return r;
}
int main () {
int *p;
p = function();
for (int j = 0;j < 10;j++)
printf("%d ",*(p+j));
return 0;
}
memset是以字节为单位,初始化内存块。
包含在头文件 <string.h> 或 <cstring>中
当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值,并可初始化二维数组,比如,
char data[10];
memset(data, 1, sizeof(data)); // right
memset(data, 0, sizeof(data)); // right
而在初始化其他基础类型时,则需要注意,比如,
int data[10];
memset(data, 0, sizeof(data)); // right
memset(data, -1, sizeof(data)); // right
memset(data, 1, sizeof(data)); // wrong, data[x] would be 0x0101 instead of 1
2. 当结构体类型中包含指针时,在使用memset初始化时需要小
心。如如下代码中,
struct Parameters {
int x;
int* p_x;
};
Parameters par;
par.p_x = new int[10];
memset(&par, 0, sizeof(par));
当memset初始化时,并不会初始化p_x指向的int数组单元的值,而会把已经分配过内存的p_x指针本身设置为0,造成内存泄漏。同理,对std::vector等数据类型,显而易见也是不应该使用memset来初始化的。