此篇為Pointers in C Programming A Modern Approach to Memory Management, Recursive Data Structures, Strings, and Arrays
這本書第五章筆記。
程式1:function-calls-multi.c
#include <assert.h>
void array_full_size(int A[10][10])
{
// A becomes a pointer to length 10 arrays
assert(sizeof A == sizeof(int (*)[10]));
assert(sizeof *A == 10 * sizeof(int));
}
void array_incomplete_size(int A[][10])
{
// A becomes a pointer to length 10 arrays
assert(sizeof A == sizeof(int (*)[10]));
assert(sizeof *A == 10 * sizeof(int));
}
void pointer(int (*A)[10])
{
// A is explicitly a pointer to length 10 arrays
assert(sizeof A == sizeof(int (*)[10]));
assert(sizeof *A == 10 * sizeof(int));
}
int main(void)
{
int A[10][10];
assert(sizeof A == 10 * 10 * sizeof(int));
array_full_size(A);
array_incomplete_size(A);
pointer(A);
int B[5][10];
assert(sizeof B == 5 * 10 * sizeof(int));
// B's first dimension is wrong, but no warnings
array_full_size(B);
array_incomplete_size(B);
pointer(B);
int C[10][5];
assert(sizeof C == 10 * 5 * sizeof(int));
// You get warnings here, because the
// second dimension doesn't match
array_full_size(C);
array_incomplete_size(C);
pointer(C);
return 0;
}
輸出:
無
程式2:function-calls.c
#include <stdio.h>
void pointer(int *a)
{
printf("pointer: %zu %zu\n", sizeof a, sizeof *a);
}
void array(int a[])
{
printf("array: %zu %zu\n", sizeof a, sizeof *a);
}
void array_with_size(int a[50])
{
printf("array[50]: %zu %zu\n", sizeof a, sizeof *a);
}
void array_with_parameter_size(int n, int a[n])
{
printf("array[n]: %zu %zu\n", sizeof a, sizeof *a);
}
void size_constrained(int a[static 4])
{
printf("size constrained a[0] == %d\n", a[0]);
}
void indirect_size_constrained(int a[static 2])
{
size_constrained(a); // No warning, though 2 < 4
}
void pointer_to_array(int (*a)[3])
{
printf("*a: %zu = %zu x %zu\n",
sizeof *a, sizeof *a / sizeof **a, sizeof **a);
}
void pointer_to_array_n(int n, int (*a)[n])
{
printf("*a with n = %d: %zu = %zu x %zu\n",
n, sizeof *a,
sizeof *a / sizeof **a, sizeof **a);
}
void indirect_pointer_to_array(int n, int (*array)[1])
{
pointer_to_array(array); // Warning, ok bcause 1 < 3
}
int main(void)
{
int n = 100;
int a[n]; a[0] = 42;
int b[2]; b[0] = 13;
int *p = b;
printf("declared: %zu %zu\n", sizeof a, sizeof *a);
pointer(a);
array(a);
array_with_size(a); // Ok, 100 > 5
array_with_size(b); // No warning although 2 < 50
array_with_parameter_size(n, a); // Ok, a has size n
array_with_parameter_size(n, b); // No warning but 2 < 100
size_constrained(b); // Warning (correct, 2 < 4)
size_constrained(p); // No warning, even though p == b
indirect_size_constrained(b); // No warning...
pointer_to_array(&a); // Ok, 100 > 3
pointer_to_array(&b); // Warning (correct 2 < 3)
pointer_to_array_n(10, &a); // Ok since 100 > 10
pointer_to_array_n(50, &b); // No warning, although 2 < 50
pointer_to_array(p); // Warning, ok since p does not point to array
pointer_to_array_n(10, p); // Warning, ditto
indirect_pointer_to_array(2, b);
return 0;
}
輸出:
declared: 400 4
pointer: 8 4
array: 8 4
array[50]: 8 4
array[50]: 8 4
array[n]: 8 4
array[n]: 8 4
size constrained a[0] == 13
size constrained a[0] == 13
size constrained a[0] == 13
*a: 12 = 3 x 4
*a: 12 = 3 x 4
*a with n = 10: 40 = 10 x 4
*a with n = 50: 200 = 50 x 4
*a: 12 = 3 x 4
*a with n = 10: 40 = 10 x 4
*a: 12 = 3 x 4
程式3:function-calls.c
#include <stdio.h>
#include <assert.h>
int main(void)
{
int array[] = { 0, 1, 2, 3, 4 };
int n = sizeof array / sizeof *array;
int *jp = array;
for (int i = 0; i < 5; i++) {
assert(array + i == jp + i);
assert(array[i] == jp[i]);
assert(array[i] == *(array + i));
assert(jp[i] == *(jp + i));
assert(i[array] == i[jp]);
}
int *ip = array;
char *p = (char *)array;
for (int i = 0; i < n; i++) {
printf("%p %p %p\n",
// int array has the right offset
(void *)(array + i),
// int * has the right offset
(void *)(ip + i),
// void * jumps in bytes...
(void *)(p + i * sizeof(int)));
}
char *end = (char *)array + sizeof array;
for (ip = array, p = (char *)array;
p != end;
ip++, p += sizeof *ip) {
printf("%p %p\n", (void *)ip, (void *)p);
}
return 0;
}
輸出:
0x7fff00748fa0 0x7fff00748fa0 0x7fff00748fa0
0x7fff00748fa4 0x7fff00748fa4 0x7fff00748fa4
0x7fff00748fa8 0x7fff00748fa8 0x7fff00748fa8
0x7fff00748fac 0x7fff00748fac 0x7fff00748fac
0x7fff00748fb0 0x7fff00748fb0 0x7fff00748fb0
0x7fff00748fa0 0x7fff00748fa0
0x7fff00748fa4 0x7fff00748fa4
0x7fff00748fa8 0x7fff00748fa8
0x7fff00748fac 0x7fff00748fac
0x7fff00748fb0 0x7fff00748fb0
程式4:jagged.c
#include <stdio.h>
#include <assert.h>
int main(void)
{
double *A[] = {
(double[]){1},
(double[]){2, 3},
(double[]){4, 5, 6}
};
int n = sizeof A / sizeof *A;
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) {
printf("%2.2f ", A[i][j]);
}
printf("\n");
}
// not true: assert(sizeof A == 6 * sizeof(double));
assert(sizeof A == 3 * sizeof(double *));
assert(sizeof A[0] == sizeof(double *));
assert(sizeof A[1] == sizeof(double *));
assert(sizeof A[2] == sizeof(double *));
double row0[] = {1};
double row1[] = {2, 3};
double row2[] = {4, 5, 6};
double *B[] = { row0, row1, row2 };
assert(sizeof B == sizeof A);
assert(sizeof B[0] == sizeof A[0]);
double **p_A = A;
assert(p_A[0] == A[0]);
assert(p_A[1] == A[1]);
assert(p_A[0][0] == A[0][0]);
double *p_A1 = A[1];
assert(p_A1[0] == A[1][0]);
assert(p_A1[1] == A[1][1]);
return 0;
}
輸出:
1.00
2.00 3.00
4.00 5.00 6.00
注意以下這些宣告方式
double *A[] = {
(double[]){1},
(double[]){2, 3},
(double[]){4, 5, 6}
};
double row0[] = {1};
double row1[] = {2, 3};
double row2[] = {4, 5, 6};
double *B[] = { row0, row1, row2 };
程式5:matrix.c(2*2
矩陣相乘)
#include <stdio.h>
void mult(int n, int m, int l,
double C[n][m],
double const A[n][l],
double const B[l][m])
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
double x = 0.0;
for (int k = 0; k < l; k++) {
x += A[i][k] * B[k][j];
}
C[i][j] = x;
}
}
}
void print_matrix(int n, int m, double const A[n][m])
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
printf("%2.2f ", A[i][j]);
}
printf("\n");
}
}
int main(void)
{
double A[2][3] = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
double B[3][2] = {
{ 1, 2 },
{ 3, 4 },
{ 5, 6 }
};
double C[2][2];
mult(2, 2, 3, C, A, B);
print_matrix(2, 2, C);
return 0;
}
輸出:
22.00 28.00
49.00 64.00
程式6:multi-dim-repr-2.c
#include <stdio.h>
int main(void)
{
int C[2][2][3] = {
{ { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } }
};
int dim1 = sizeof C / sizeof C[0];
int dim2 = sizeof C[0] / sizeof C[0][0];
int dim3 = sizeof C[0][0] / sizeof C[0][0][0];
printf("C dimensions %d x %d x %d\n", dim1, dim2, dim3);
printf("First element in each row: ");
int (*first_dim_p)[2][3] = C;
int (*first_end)[2][3] = C + dim1;
for ( ; first_dim_p < first_end; first_dim_p++) {
printf("%d ", *(int*)first_dim_p);
}
printf("\n");
printf("First element in each column: ");
int (*second_dim_p)[3] = (int (*)[3])C;
int (*second_end)[3] = (int (*)[3])C + dim1 * dim2;
for ( ; second_dim_p < second_end; second_dim_p++) {
printf("%d ", *(int*)second_dim_p);
}
printf("\n");
return 0;
}
輸出:
C dimensions 2 x 2 x 3
First element in each row: 1 7
First element in each column: 1 4 7 10
程式7:multi-dim-repr.c
#include <assert.h>
int main(void)
{
int A[2][3] = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
assert(sizeof A == 2 * 3 * sizeof(int));
assert(sizeof *A == 3 * sizeof(int));
assert(sizeof A[0] == 3 * sizeof(int));
assert(sizeof A[0][0] == sizeof(int));
int *p = (int *)A;
for (int i = 0; i < 2; i++) {
// p now points to the first element in row i
assert(p == A[i]);
for (int j = 0; j < 3; j++) {
// p points to column j in row i
assert(A[i] + j == p);
assert(&A[i][j] == p);
assert(A[i][j] == *p);
p++;
}
}
int B[2][2][3] = {
{ { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } }
};
assert(sizeof B == 2 * 2 * 3 * sizeof(int));
assert(sizeof B[0] == 2 * 3 * sizeof(int));
assert(sizeof B[0][0] == 3 * sizeof(int));
assert(sizeof B[0][0][0] == sizeof(int));
p = (int *)B;
for (int i = 0; i < 2; i++) {
// p now points to row i
assert(p == (int *)B[i]);
for (int j = 0; j < 2; j++) {
// p now points to column j in row i
assert(p == (int *)(B[i] + j));
for (int k = 0; k < 3; k++) {
// p now points to the k'th element in B[i][j]
assert(B[i][j] + k == p);
assert(&B[i][j][k] == p);
assert(B[i][j][k] == *p);
p++;
}
}
}
return 0;
}
輸出:
無
程式8:pointers-arrays.c
#include <stdio.h>
#include <assert.h>
void not_what_you_want(int array[])
{
// sizeof(array) is sizeof(int *) here!
printf("%zu\n", sizeof array);
// Here, the array and the address of the array
// are different. array is a local variable
// that holds a pointer to the array!
printf("%p %p\n", (void *)array, (void *)&array);
}
int main(void)
{
int array[] = { 1, 2, 3, 4, 5 };
int *ap = array;
int (*ap2)[] = &array;
printf("sizeof array == %zu, sizeof ap == %zu, sizeof ap2 == %zu, sizeof *ap2\n",
sizeof array, sizeof ap, sizeof ap2);
printf("%p %p %p %p %p %p\n", (void *)array, (void *)&array,
(void *)ap, (void *)&ap, (void *)ap2, (void *)&ap2);
int n = sizeof array / sizeof *array;
for (int i = 0; i < n; i++) {
assert(array[i] == ap[i]);
assert(array + i == ap + i);
assert(*(array + i) == *(ap + i));
}
return 0;
}
輸出:
sizeof array == 20, sizeof ap == 8, sizeof ap2 == 8, sizeof *ap2
0x7fff3ecc55e0 0x7fff3ecc55e0 0x7fff3ecc55e0 0x7fff3ecc55d0 0x7fff3ecc55e0 0x7fff3ecc55d8
程式9:pointers-to-arrays.c
#include <stdio.h>
int main(void)
{
int array[10];
int (*ap1)[] = &array;
int (*ap2)[10] = &array;
int (*ap3)[5] = &array; // Warning
int (*ap4)[20] = &array; // Warning
int *ip = array;
printf("%p, sizeof array == %zu\n", (void *)array, sizeof array);
// We cannot get sizeof *ap1, it is an incomplete type.
printf("%p\n", (void *)*ap1);
printf("%p, sizeof *ap2 == %zu (%zu)\n",
(void *)*ap2, sizeof *ap2, 10 * sizeof(int));
printf("%p, sizeof *ap3 == %zu (%zu)\n",
(void *)*ap3, sizeof *ap3, 5 * sizeof(int));
printf("%p, sizeof *ap4 == %zu (%zu)\n",
(void *)*ap4, sizeof *ap4, 20 * sizeof(int));
printf("%p, sizeof *ip == %zu (%zu)\n",
(void *)ip, sizeof ip, sizeof(int *));
return 0;
}
輸出:
0x7ffe61ad0000, sizeof array == 40
0x7ffe61ad0000
0x7ffe61ad0000, sizeof *ap2 == 40 (40)
0x7ffe61ad0000, sizeof *ap3 == 20 (20)
0x7ffe61ad0000, sizeof *ap4 == 80 (80)
0x7ffe61ad0000, sizeof *ip == 8 (8)
程式10:simple.c
#include <stdio.h>
void add_array(int n, int array[n], int x)
{
for (int i = 0; i < n; i++) {
array[i] += x;
}
}
void add_pointers(int *begin, int *end, int x)
{
for ( ; begin < end; begin++) {
*begin += x;
}
}
int sum_array(int n, int array[n])
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += array[i];
}
return sum;
}
int sum_pointers_(int *begin, int *end)
{
int sum = 0;
for ( ; begin < end; begin++) {
sum += *begin;
}
return sum;
}
int sum_pointers(int *begin, int *end)
{
int sum = 0;
while (begin < end) {
sum += *begin++;
}
return sum;
}
void swap_array(int array[], int i, int j)
{
int tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
void reverse_array(int n, int array[n])
{
for (int i = 0; i < n/2; i++) {
swap_array(array, i, n - i - 1);
}
}
void swap_pointers(int *i, int *j)
{
int tmp = *i;
*i = *j;
*j = tmp;
}
void reverse_pointers(int *begin, int *end)
{
if (end <= begin) return;
end--; // point to last element
while (begin < end) {
swap_pointers(begin++, end--);
}
}
void print_array(int n, int array[n])
{
printf("[ ");
for (int i = 0; i < n; i++)
printf("%d ", array[i]);
printf("]\n");
}
int main(void)
{
int array[] = { 1, 2, 3, 4, 5 };
int n = sizeof array / sizeof *array;
add_array(n, array, 2);
print_array(n, array);
add_pointers(array, array + n, -2);
print_array(n, array);
printf("%d %d\n",
sum_array(n, array),
sum_pointers(array, array + n));
reverse_array(n, array);
print_array(n, array);
reverse_pointers(array, array + n);
print_array(n, array);
return 0;
}
輸出:
[ 3 4 5 6 7 ]
[ 1 2 3 4 5 ]
15 15
[ 5 4 3 2 1 ]
[ 1 2 3 4 5 ]
程式11:void.c
#include <stdio.h>
int main(int argc, char **argv)
{
void *vp = 0;
char *cp = 0;
int *ip = 0;
long *lp = 0;
for (int i = 0; i < 5; i++) {
char *p = vp; // so we can do arithmetic
printf("char: %p %p ", cp + i, p + i * sizeof(char));
printf("int: %p %p ", ip + i, p + i * sizeof(int));
printf("long: %p %p\n", lp + i, p + i * sizeof(long));
}
return 0;
}
輸出:
char: (nil) (nil) int: (nil) (nil) long: (nil) (nil)
char: 0x1 0x1 int: 0x4 0x4 long: 0x8 0x8
char: 0x2 0x2 int: 0x8 0x8 long: 0x10 0x10
char: 0x3 0x3 int: 0xc 0xc long: 0x18 0x18
char: 0x4 0x4 int: 0x10 0x10 long: 0x20 0x20