最近在写一道算法题目时犯了一个关于C语言的指针的错误,写下这篇帖子记录一下,避免再犯。
错误主要关于传递一个初始长度不定的二维数组参数,然后通过指针的方式读写该数组。主要错误代码如下:
#include <stdio.h>
#include <stdlib.h>
#define N 5 //假设N大于2且在程序运行之前是未定的
void PointerTest(char ** param );
int main()
{
char test[N][N];
int i ,j;
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
test[i][j] = -1;
PointerTest(test );
return 0;
}
void PointerTest(char ** param)
{
char temp;
temp = param[1][1];//此句发生错误
}
每次执行到 temp = param[1][1];时就会发生错误,提示非法访问。
我苦逼的在调用之前各种找,各种检查,就是没发现错误。后来仔细检查指针才发现是指针的使用出错了。
param是一个char**类型的形参,所以param[0]=*param,*param是一个char*型的变量,所以*param是一个指针数据四个字节,就是原数组test[0][0]~test[0][3]的数据。而原数组test[0]是一个char[5]型数据,就是指向test[0][0]的指针。也就是说若test地址为0x00123456,param+1的地址就是0x123456+4=0x12345A,一个指针的长度;而test+1的地址就是0x123456+5=0x12345B,一个char[5]的长度。
这样也就能解释访问param[1][1]出错了,因为param[1]的值是test[0][4]~test[0][7],是非法的地址空间。
因此要正确的访问就应该使用*(param+i)这种方式读取test数组的值。
下面一段程序就很直观的显示了我所犯的的错误。
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
void PointerTest(char ** param1 ,char param2[][5]);
int main()
{
char test[5][5];
int i ,j,m=0;
for (i = 0; i < 5; i++)
for (j = 0; j < 5; j++)
test[i][j] = m++;
PointerTest(test ,test);
return 0;
}
void PointerTest(char ** param1 ,char param2[][5])
{
printf("Param1 Addr=0x%08X\n",param1);
printf("Param2 Addr=0x%08X\n" ,param2);
printf("Param1 size=0x%08X\n" ,sizeof(param1));
printf("Param2 size=0x%08X\n" ,sizeof(param2));
printf("****************************\n");
printf("*Param1 Addr=0x%08X\n" ,*param1);
printf("*Param2 Addr=0x%08X\n" ,*param2);
printf("****************************\n");
printf("*Param1+1 Addr=0x%08X\n" ,*(param1 + 1));
printf("*Param2+1 Addr=0x%08X\n" ,*(param2 + 1));
printf("****************************\n");
printf("Param1[0] Addr=0x%08X\n" ,param1[0]);
printf("Param1[1] Addr=0x%08X\n" ,param1[1]);
printf("Param1[2] Addr=0x%08X\n" ,param1[2]);
printf("------------------------------\n");
printf("Param2[0] Addr=0x%08X\n" ,param2[0]);
printf("Param2[1] Addr=0x%08X\n" ,param2[1]);
printf("Param2[2] Addr=0x%08X\n" ,param2[2]);
printf("****************************\n");
printf("Param1[0][0] Addr=0x%08X\n" ,¶m1[1][1]);
printf("Param2[0][0] Addr=0x%08X\n" ,¶m2[0][0]);
printf("****************************\n");
system("pause");
return;
}