#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#define NOBADCALLS
#define NROWS 3
#define NCOLUMNS 5
#define Arrayval(array, ncolumns, i, j) array[i * ncolumns + j]
int main(int, char *[]);
void f(int array[][NCOLUMNS], int nrows, int ncolumns);
void f2(int *array, int nrows, int ncolumns);
void f3(int **array, int nrows, int ncolumns);
void f4(int nrows, int ncolumns, int array[nrows][ncolumns]);
int not /* = 0 */;
int
main(int argc, char *argv[])
{
int nrows = NROWS;
int ncolumns = NCOLUMNS;
int array[NROWS][NCOLUMNS]; //一次性的分配连续空间的内存,数组名array本身如果作为函数入参会退化为int (*)[NCOLUMNS] 类型
int **array1; //分配了非连续的内存空间来存储整个数组内容
int **array2; //<span style="font-family: Arial, Helvetica, sans-serif;">分配了连续的内存空间来存储整个数组内容</span>
int *array3;
int (*array4)[NCOLUMNS]; //直接分配了连续空间
int i, j;
int *ip;
array1 = (int **)malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++)
array1[i] = (int *)malloc(ncolumns * sizeof(int));//注意这里,三次分配内存,导致内存空间不一致了
array2 = (int **)malloc(nrows * sizeof(int *));
array2[0] = (int *)malloc(nrows * ncolumns * sizeof(int));
for(i = 1; i < nrows; i++)
array2[i] = array2[0] + i * ncolumns;
array3 = (int *)malloc(nrows * ncolumns * sizeof(int));
array4 = (int (*)[NCOLUMNS])malloc(nrows * sizeof(*array4));
for(i = 0; i < nrows; i++)
{
for(j = 0; j < ncolumns; j++)
{
array[i][j] = 10 * i + j;
array1[i][j] = 100 + 10 * i + j;
array2[i][j] = 200 + 10 * i + j;
Arrayval(array3, ncolumns, i, j) = 300 + 10 * i + j;
array4[i][j] = 400 + 10 * i + j;
}
}
printf("as arrays:\n\n");
printf("array:\n");
f(array, NROWS, NCOLUMNS);
#ifndef NOBADCALLS
printf("\narray1 (shouldn't work):\n");
f((int (*)[NCOLUMNS])array1, nrows, ncolumns); /* outright wrong cast */ //其实可以换成 <span style="font-family: Arial, Helvetica, sans-serif;">f((int (*)[NCOLUMNS])(*array1), nrows, ncolumns),其结果是能够正确打印第一行的数据,但是却无法正确定位第二行数据,原因就在于使用a[i][j]这种方法定位数据是以首地址a为起始点,然后进行i*j + j这种指针偏移,而偏偏array1的初始化数据的内存空间并不一致</span>
if(not) f(array1, nrows, ncolumns); /* to check for compiler warnings */
#endif
printf("\narray2:\n");
f((int (*)[NCOLUMNS])(*array2), nrows, ncolumns); /* questionable cast */
if(not) f(*array2, nrows, ncolumns); /* to check for compiler warnings */
printf("\narray3:\n");
f((int (*)[NCOLUMNS])array3, nrows, ncolumns); /* questionable cast */
if(not) f(array3, nrows, ncolumns); /* to check for compiler warnings */
printf("\narray4:\n");
f(array4, nrows, ncolumns);
printf("\n\nas \"simulated\" arrays:\n\n");
printf("array:\n");
f2(&array[0][0], NROWS, NCOLUMNS);
#ifndef NOBADCALLS
printf("\narray1 (shouldn't work):\n");
f2((int *)array1, nrows, ncolumns); /* outright wrong cast */
if(not) f2(array1, nrows, ncolumns); /* to check for compiler warnings */
printf("\narray1 another way (also shouldn't work):\n");
f2(*array1, nrows, ncolumns);
#endif
printf("\narray2:\n");
f2(*array2, nrows, ncolumns);
printf("\narray3:\n");
f2(array3, nrows, ncolumns);
printf("\narray4:\n");
f2(*array4, nrows, ncolumns);
printf("\narray4 another way (should also work):\n");
f2((int *)array4, nrows, ncolumns); /* questionable cast */
if(not) f2(array4, nrows, ncolumns); /* to check for compiler warnings */
printf("\n\nas pointers:\n\n");
#ifndef NOBADCALLS
printf("array (shouldn't work):\n");
f3((int **)array, NROWS, NCOLUMNS); /* outright wrong cast */
if(not) f3(array, NROWS, NCOLUMNS); /* to check for compiler warnings */
printf("\narray another way (also shouldn't work):\n");
ip = &array[0][0];
f3(&ip, NROWS, NCOLUMNS);
#endif
printf("\narray1:\n");
f3(array1, nrows, ncolumns);
printf("\narray2:\n");
f3(array2, nrows, ncolumns);
#ifndef NOBADCALLS
printf("\narray3 (shouldn't work):\n");
f3((int **)array3, nrows, ncolumns); /* outright wrong cast */
if(not) f3(array3, nrows, ncolumns); /* to check for compiler warnings */
printf("\narray3 another way (also shouldn't work):\n");
f3(&array3, nrows, ncolumns);
printf("\narray4 (shouldn't work):\n");
f3((int **)array4, nrows, ncolumns); /* outright wrong cast */
if(not) f3(array4, nrows, ncolumns); /* to check for compiler warnings */
printf("\narray4 another way (also shouldn't work):\n");
f3((int **)&array4, nrows, ncolumns); /* outright wrong cast */
if(not) f3(&array4, nrows, ncolumns); /* to check for compiler warnings */
printf("\narray4 yet another way (also shouldn't work):\n");
ip = array4; /* should warn */
ip = (int *)array4; /* outright wrong cast */
f3(&ip, nrows, ncolumns);
printf("\narray4 one last way (certainly shouldn't work):\n");
ip = &array4; /* should warn */
ip = (int *)&array4; /* outright wrong cast */
f3(&ip, nrows, ncolumns);
#endif
printf("\n\nas variable-length arrays:\n\n");
printf("array:\n");
f4(NROWS, NCOLUMNS, array);
#ifndef NOBADCALLS
printf("\narray1 (shouldn't work):\n");
f4(nrows, ncolumns, (int (*)[NCOLUMNS])array1); /* outright wrong cast */
if(not) f4(nrows, ncolumns, array1); /* to check for compiler warnings */
#endif
printf("\narray2:\n");
f4(nrows, ncolumns, (int (*)[NCOLUMNS])(*array2)); /* questionable cast */
if(not) f4(nrows, ncolumns, *array2); /* to check for compiler warnings */
printf("\narray3:\n");
f4(nrows, ncolumns, (int (*)[NCOLUMNS])array3); /* questionable cast */
if(not) f4(nrows, ncolumns, array3); /* to check for compiler warnings */
printf("\narray4:\n");
f4(nrows, ncolumns, array4);
return 0;
}
void
f(int array[][NCOLUMNS], int nrows, int ncolumns)
{
int i, j;
for(i = 0; i < nrows; i++)
{
for(j = 0; j < ncolumns; j++)
{
if(j != 0)
printf("\t");
printf("%03d", array[i][j]);
}
printf("\n");
}
}
void
f2(int *array, int nrows, int ncolumns)
{
int i, j;
for(i = 0; i < nrows; i++)
{
for(j = 0; j < ncolumns; j++)
{
if(j != 0)
printf("\t");
printf("%03d", Arrayval(array, ncolumns, i, j));
}
printf("\n");
}
}
void
f3(int **array, int nrows, int ncolumns)
{
int i, j;
for(i = 0; i < nrows; i++)
{
for(j = 0; j < ncolumns; j++)
{
if(j != 0)
printf("\t");
printf("%03d", array[i][j]);
}
printf("\n");
}
}
void
f4(int nrows, int ncolumns, int array[nrows][ncolumns])
{
int i, j;
for(i = 0; i < nrows; i++)
{
for(j = 0; j < ncolumns; j++)
{
if(j != 0)
printf("\t");
printf("%03d", array[i][j]);
}
printf("\n");
}
}
not define NOBADCALLS and only compile, to get all warning
make aa.o
gcc -g -c aa.c
aa.c: In function ‘main’:
aa.c:67:2: warning: passing argument 1 of ‘f’ from incompatible pointer type [enabled by default]
if(not) f(array1, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:13:7: note: expected ‘int (*)[5]’ but argument is of type ‘int **’
void f(int array[][NCOLUMNS], int nrows, int ncolumns);
^
aa.c:73:2: warning: passing argument 1 of ‘f’ from incompatible pointer type [enabled by default]
if(not) f(*array2, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:13:7: note: expected ‘int (*)[5]’ but argument is of type ‘int *’
void f(int array[][NCOLUMNS], int nrows, int ncolumns);
^
aa.c:77:2: warning: passing argument 1 of ‘f’ from incompatible pointer type [enabled by default]
if(not) f(array3, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:13:7: note: expected ‘int (*)[5]’ but argument is of type ‘int *’
void f(int array[][NCOLUMNS], int nrows, int ncolumns);
^
aa.c:91:2: warning: passing argument 1 of ‘f2’ from incompatible pointer type [enabled by default]
if(not) f2(array1, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:14:7: note: expected ‘int *’ but argument is of type ‘int **’
void f2(int *array, int nrows, int ncolumns);
^
aa.c:107:2: warning: passing argument 1 of ‘f2’ from incompatible pointer type [enabled by default]
if(not) f2(array4, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:14:7: note: expected ‘int *’ but argument is of type ‘int (*)[5]’
void f2(int *array, int nrows, int ncolumns);
^
aa.c:115:2: warning: passing argument 1 of ‘f3’ from incompatible pointer type [enabled by default]
if(not) f3(array, NROWS, NCOLUMNS); /* to check for compiler warnings */
^
aa.c:15:7: note: expected ‘int **’ but argument is of type ‘int (*)[5]’
void f3(int **array, int nrows, int ncolumns);
^
aa.c:132:2: warning: passing argument 1 of ‘f3’ from incompatible pointer type [enabled by default]
if(not) f3(array3, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:15:7: note: expected ‘int **’ but argument is of type ‘int *’
void f3(int **array, int nrows, int ncolumns);
^
aa.c:138:2: warning: passing argument 1 of ‘f3’ from incompatible pointer type [enabled by default]
if(not) f3(array4, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:15:7: note: expected ‘int **’ but argument is of type ‘int (*)[5]’
void f3(int **array, int nrows, int ncolumns);
^
aa.c:141:2: warning: passing argument 1 of ‘f3’ from incompatible pointer type [enabled by default]
if(not) f3(&array4, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:15:7: note: expected ‘int **’ but argument is of type ‘int (**)[5]’
void f3(int **array, int nrows, int ncolumns);
^
aa.c:143:5: warning: assignment from incompatible pointer type [enabled by default]
ip = array4; /* should warn */
^
aa.c:147:5: warning: assignment from incompatible pointer type [enabled by default]
ip = &array4; /* should warn */
^
aa.c:162:2: warning: passing argument 3 of ‘f4’ from incompatible pointer type [enabled by default]
if(not) f4(nrows, ncolumns, array1); /* to check for compiler warnings */
^
aa.c:16:7: note: expected ‘int (*)[(sizetype)(ncolumns)]’ but argument is of type ‘int **’
void f4(int nrows, int ncolumns, int array[nrows][ncolumns]);
^
aa.c:168:2: warning: passing argument 3 of ‘f4’ from incompatible pointer type [enabled by default]
if(not) f4(nrows, ncolumns, *array2); /* to check for compiler warnings */
^
aa.c:16:7: note: expected ‘int (*)[(sizetype)(ncolumns)]’ but argument is of type ‘int *’
void f4(int nrows, int ncolumns, int array[nrows][ncolumns]);
^
aa.c:172:2: warning: passing argument 3 of ‘f4’ from incompatible pointer type [enabled by default]
if(not) f4(nrows, ncolumns, array3); /* to check for compiler warnings */
^
aa.c:16:7: note: expected ‘int (*)[(sizetype)(ncolumns)]’ but argument is of type ‘int *’
void f4(int nrows, int ncolumns, int array[nrows][ncolumns]);
define NOBADCALLS and start run (otherwise you will face crash)
make
gcc -g -c aa.c
aa.c: In function ‘main’:
aa.c:73:2: warning: passing argument 1 of ‘f’ from incompatible pointer type [enabled by default]
if(not) f(*array2, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:13:7: note: expected ‘int (*)[5]’ but argument is of type ‘int *’
void f(int array[][NCOLUMNS], int nrows, int ncolumns);
^
aa.c:77:2: warning: passing argument 1 of ‘f’ from incompatible pointer type [enabled by default]
if(not) f(array3, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:13:7: note: expected ‘int (*)[5]’ but argument is of type ‘int *’
void f(int array[][NCOLUMNS], int nrows, int ncolumns);
^
aa.c:107:2: warning: passing argument 1 of ‘f2’ from incompatible pointer type [enabled by default]
if(not) f2(array4, nrows, ncolumns); /* to check for compiler warnings */
^
aa.c:14:7: note: expected ‘int *’ but argument is of type ‘int (*)[5]’
void f2(int *array, int nrows, int ncolumns);
^
aa.c:168:2: warning: passing argument 3 of ‘f4’ from incompatible pointer type [enabled by default]
if(not) f4(nrows, ncolumns, *array2); /* to check for compiler warnings */
^
aa.c:16:7: note: expected ‘int (*)[(sizetype)(ncolumns)]’ but argument is of type ‘int *’
void f4(int nrows, int ncolumns, int array[nrows][ncolumns]);
^
aa.c:172:2: warning: passing argument 3 of ‘f4’ from incompatible pointer type [enabled by default]
if(not) f4(nrows, ncolumns, array3); /* to check for compiler warnings */
^
aa.c:16:7: note: expected ‘int (*)[(sizetype)(ncolumns)]’ but argument is of type ‘int *’
void f4(int nrows, int ncolumns, int array[nrows][ncolumns]);
^
gcc -g -o aa aa.o
./aa
as arrays:
array:
000 001 002 003 004
010 011 012 013 014
020 021 022 023 024
array2:
200 201 202 203 204
210 211 212 213 214
220 221 222 223 224
array3:
300 301 302 303 304
310 311 312 313 314
320 321 322 323 324
array4:
400 401 402 403 404
410 411 412 413 414
420 421 422 423 424
as "simulated" arrays:
array:
000 001 002 003 004
010 011 012 013 014
020 021 022 023 024
array2:
200 201 202 203 204
210 211 212 213 214
220 221 222 223 224
array3:
300 301 302 303 304
310 311 312 313 314
320 321 322 323 324
array4:
400 401 402 403 404
410 411 412 413 414
420 421 422 423 424
array4 another way (should also work):
400 401 402 403 404
410 411 412 413 414
420 421 422 423 424
as pointers:
array1:
100 101 102 103 104
110 111 112 113 114
120 121 122 123 124
array2:
200 201 202 203 204
210 211 212 213 214
220 221 222 223 224
as variable-length arrays:
array:
000 001 002 003 004
010 011 012 013 014
020 021 022 023 024
array2:
200 201 202 203 204
210 211 212 213 214
220 221 222 223 224
array3:
300 301 302 303 304
310 311 312 313 314
320 321 322 323 324
array4:
400 401 402 403 404
410 411 412 413 414
420 421 422 423 424