讨论/技术交流/菜狗求教C语言中,二维数组做参数,退化为二级指针的问题。/
菜狗求教C语言中,二维数组做参数,退化为二级指针的问题。

直接上代码吧
我自己写的时候,总是报错,但是看别人写的就能通过。
这个问题一直困扰着我,实在不明白,望大家指教。

typedef struct {
    int** mat;
    int matSize;
    int matColSize;
} NumMatrix;
NumMatrix* numMatrixCreate(int** matrix, int matrixSize, int* matrixColSize) {
    int i,j;
    NumMatrix* obj;

    if((NULL == matrix) || (NULL == matrix[0]) || (NULL == matrixColSize))
    {
        return NULL;
    }

    printf("%p\n", matrix);

    obj = (NumMatrix*)malloc(sizeof(NumMatrix));

    obj->matSize = matrixSize;
    obj->matColSize = matrixColSize[0];

    obj->mat = (int**)malloc(sizeof(int*) * (matrixSize+1));

    for(i=0; i<matrixSize; i++)
    {
        obj->mat[i] = (int*)malloc(sizeof(int) * (matrixColSize[0]+1));
        memcpy(obj->mat[i], matrix[i], matrixColSize[0]);// <<< 出错行
    }

    return obj;
}

也就是说使用 matrix[i] 去访问二维指针,会报错。
还有,我访问 matrix[i][j] 的时候,也会报错。如下:

bool findNumberIn2DArray(int** matrix, int matrixSize, int* matrixColSize, int target){
    int i,j;
	
	if (matrix == NULL || matrixSize == 0 || matrixColSize[0] == 0) {
		return false;
	}

	
    for(i=1; i<=matrixColSize[0]; i++)
    {
        if( matrix[0][matrixColSize[0]-i] < target) //<<<这行matrix[i][j]出错
        {
            //得到目标列
            break;
        }
        if( matrix[0][matrixColSize[0]-i] == target)
        {
            return true;
        }
        
    }
    if(matrixColSize[0] == i)
    {
        return false;
    }

    for(j=1; j<=matrixSize-1; j++)
    {
        if(matrix[j][matrixColSize[0]-i] == target)
        {
            return true;
        }
    }

    return false;
}

但是我看别人,包括官方的回答,都是直接 matrix[i][j] 访问的呀,他们不报错,合着就我自己报错啊。。。。

下边是官方写的代码:

NumMatrix* numMatrixCreate(int** matrix, int matrixSize, int* matrixColSize) {
    NumMatrix* ret = malloc(sizeof(NumMatrix));
    ret->sums = malloc(sizeof(int*) * matrixSize);
    ret->sumsSize = matrixSize;
    for (int i = 0; i < matrixSize; i++) {
        ret->sums[i] = malloc(sizeof(int) * (matrixColSize[i] + 1));
        ret->sums[i][0] = 0;
        for (int j = 0; j < matrixColSize[i]; j++) {
            ret->sums[i][j + 1] = ret->sums[i][j] + matrix[i][j];//<<<这行matrix[i][j]不出错!??
        }
    }
    return ret;
}
/*
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/range-sum-query-2d-immutable/solution/er-wei-qu-yu-he-jian-suo-ju-zhen-bu-ke-b-2z5n/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/

希望大家帮我解答一下,,谢谢。

1
共 13 个回复

obj->mat = (int**)malloc(sizeof(int*) * (matrixSize+1));你只把二维指针申请了,但是你没申请二维指针指向的一维指针。

obj->mat[i]=(int*)malloc(sizeof(int)*需要的个数);

1

请问一下,你本地编译器是哪个?或者ide是哪个?

C语言中,没有找到这样的用法,leetcode代码,拷贝到本地也是不能用的。

只搜到了C++中的动态数组,可以实现这种用法,附别人博客链接:https://www.cnblogs.com/usa007lhy/p/3286186.html

你的两段代码我放本地运行了下并没有报错呀?

typedef struct {
	int** mat;
	int matSize;
	int matColSize;
} NumMatrix;

NumMatrix* numMatrixCreate(int** matrix, int matrixSize, int* matrixColSize) {
	int i, j;
	NumMatrix* obj;

	if ((NULL == matrix) || (NULL == matrix[0]) || (NULL == matrixColSize))
	{
		return NULL;
	}

	printf("%p\n", matrix);

	obj = (NumMatrix*)malloc(sizeof(NumMatrix));

	obj->matSize = matrixSize;
	obj->matColSize = matrixColSize[0];

	obj->mat = (int**)malloc(sizeof(int*) * (matrixSize + 1));

	for (i = 0; i<matrixSize; i++)
	{
		obj->mat[i] = (int*)malloc(sizeof(int) * (matrixColSize[0] + 1));
		memcpy(obj->mat[i], matrix[i], matrixColSize[0]);// <<< 出错行
	}

	return obj;
}

bool findNumberIn2DArray(int** matrix, int matrixSize, int* matrixColSize, int target) {
	int i, j;

	if (matrix == NULL || matrixSize == 0 || matrixColSize[0] == 0) {
		return false;
	}


	for (i = 1; i <= matrixColSize[0]; i++)
	{
		if (matrix[0][matrixColSize[0] - i] < target) //<<<这行matrix[i][j]出错
		{
			//得到目标列
			break;
		}
		if (matrix[0][matrixColSize[0] - i] == target)
		{
			return true;
		}

	}
	if (matrixColSize[0] == i)
	{
		return false;
	}

	for (j = 1; j <= matrixSize - 1; j++)
	{
		if (matrix[j][matrixColSize[0] - i] == target)
		{
			return true;
		}
	}

	return false;
}



void main() {
	int matrix[5][5] = { { 3, 0, 1, 4, 2 },{ 5, 6, 3, 2, 1 },{ 1, 2, 0, 1, 5 },{ 4, 1, 0, 1, 7 },{ 1, 0, 3, 0, 5 } };
	int **p;
	int matrixColSize[] = { 5, 5, 5, 5, 5 };
	TRANSARRAY_INT(matrix, 5, p);
	ARRAY2DTRAVERSE_INT(p, 5, 5, 1);

	NumMatrix* obj = numMatrixCreate(p, 5, matrixColSize);
	bool x = findNumberIn2DArray(p, 5, matrixColSize, 9);

	printf("Finish! \nobj = %x, x = %d\n", obj, x);
}

//输出:
//[
//	[3, 0, 1, 4, 2],
//	[5, 6, 3, 2, 1],
//	[1, 2, 0, 1, 5],
//	[4, 1, 0, 1, 7],
//	[1, 0, 3, 0, 5]
//]
//00D25C58
//Finish!
//obj = d25c98, x = 0
//请按任意键继续. . .

如果你在LeetCode的编辑器上写matrix[i][j]也出错那么多半是越界错导致访问异常,你可以printf检查一下出错前的i, j值看看是否越界了

你说的是对的、
但是代码3是官方给出的代码,他就可以用形参matrix直接 matrix[i][j] 取值。
而我在代码2中也是使用 matrix[i][j] 的方式使用的,
官方代码对,而我的不对,
就很奇怪。。。

二维数组传参的问题我以前遇到过,简单来说就是 数组名等效于指针但不是指针
这是之前写的解释:
因为二维数组的数组名并不是二级指针,而是指向二维数组首个元素(这个元素是一维数组)的一级指针, 该指针的值是第一个元素(一维数组)的地址,而一维数组的地址即首个元素的地址,所以二维数组数组名实际上也就是指向该数组首个元素的指针,而若数组名以(int **matrix)这种传参方式传给函数后matrix是一个二级指针,matrix[0]就是数组首个元素的值(但编译器会把这个值当地址看),而matrix[0][0]就是到matrix[0]这个地址访问取值,显然是不对的。
想要在传参后使用matrix[i][j]的办法调用,那么就要求matrix[i]是一个指针而不是数组的值,所以答主将main中的matrix定义为指针数组(即数组元素是指针,区别二维数组元素是数组),那么matrix[i][j]就是合理的
写了个小的测试用例,可以证实上述内容

int main() {
	int nums[3][4] = { { 1, 2, 3, 4 },{ 4, 5, 6, 7 },{ 7, 8, 9, 10 } };
	int **q;
	q = (int **)nums;
	printf("nums = %x  nums[0] = %x  &nums[0][0] = %x  q = %x   q[0] = %x\n", nums, nums[0], &(nums[0][0]), q, q[0]);
	return 1;
}
//结果: nums = 57f740  nums[0] = 57f740  &nums[0][0] = 57f740  q = 57f740   q[0] = 1`
//如果要取q[0][0]的值,那么程序就会到地址为q[0]即1的地方去取值,就会出错

这个是二级指针作为行参时的一个陷阱。你在堆上申请的空间不一定是连续的,在作为参数时会默认按照连续空间去映射内存,会导致内存映射出错。相反,如果是在栈上的连续空间,就可以按照默认的连续空间映射方式去使用了。

好吧,我瞎了,不过你貌似没把最后一个二级指针的指向声明,虽然对那行出错没啥改变,试试用VSCODE debug下?

你对matrixColSize的理解错了,传入参数之所以类型是int* matrixColSize,就意味着matrixColSize[0]与matrixColSize[1]的值可能不一样,也就是说这个二维数组不是一个正方形或长方形的二维数组,各个列可能长度不一样。

而你的代码里面用matrixColSize[0]替代了所有列的长度,所以存在访问越界的情况。官方代码的边界用的是matrixColSize[i],而不是全部用matrixColSize[0].

    for (int j = 0; j < matrixColSize[i]; j++) {
        ret->sums[i][j + 1] = ret->sums[i][j] + matrix[i][j];//<<<这行matrix[i][j]不出错!??
    }