C 語言練習程式(6) -- 指標相關程式集錦(5)


Posted by nathan2009729 on 2022-07-30

此篇為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

#c pointer #c array #matrix







Related Posts

Day 111

Day 111

forEach 和 for迴圈

forEach 和 for迴圈

flexbox 子元素 的語法

flexbox 子元素 的語法


Comments