天天看點

多元數組和指針

一維數組名即是一個指針常量,它代表數組第一個元素的位址,知道一維數組的長度,那麼可以通過數組名輸出一維數組的所有元素:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.     int i;
  5.     int a[5] = {1, 2, 3, 4, 5};
  6.     int *p = a;
  7.     for( i = 0; i < 5; i++ )
  8.         printf( "%d\n", *(p + i) );
  9.     return 0;
  10. }

但在多元數組中,數組名卻是第一個數組的位址,怎麼了解呢?比如說定義一個二維數組:

  1. int a[2][5] = {1, 2, 3, 4, 5, 
  2.                6, 7, 8, 9, 10};

那麼數組名a就是二維數組的第一行一維數組的位址,而不要錯誤的認為它代表的是第一行第一個元素的位址,那我們應該怎麼正确的申明一個指向整形數組的指針呢? int (*p)[5] = a; 它使 p 指向二維數組的第一行的一維數組(注意是指向的第一行一維數組)。

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.     int i;
  5.     int a[2][5] = {1, 2, 3, 4, 5, 
  6.                    6, 7, 8, 9, 10};
  7.     int (*p)[5] = a;
  8.     for( i = 0; i < 5; i++ )
  9.         printf( "%d\n", *(*p + i) );
  10.     return 0;
  11. }

上面的程式也是依次輸出了1~5,這裡 p 是指向二維數組的第一行位址的指針,那麼 *p 即是代表第一行數組,那麼也就是第一行數組的位址,我們可以再通過 *(*p + i) 輸出第一行數組的各個元素。有點亂?呵呵,再仔細想想,或者直接說 a 是指向的第一行,那麼 *a 就代表第一行的那個一維數組,但 *a 仍然是一個指針常量,而 **a 才是這個一維數組的第一個元素的值。

如果我們要定義一個指針可以逐個通路元素呢?下面兩種方法都是正确的聲明和指派: int *p = &a[0][0]; int *p = a[0]; 第一種方法,就幹脆把數組的第一行第一個元素取位址給指針變量p,這可能是最直覺的方法。 第二種方法,其實原理一樣,前面剛說了 a 是指向的第一行,第一行是一個一維數組,那麼a[0]就是這個一維數組的第一個元素的位址。特别注意這裡的 a[0] 不是一個值,而是一個位址。

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.     int i;
  5.     int a[2][5] = {1, 2, 3, 4, 5, 
  6.                    6, 7, 8, 9, 10};
  7.     int *p = a[0];
  8.     for( i = 0; i < 10; i++ )
  9.         printf( "%d\n", *(p + i) );
  10.     return 0;
  11. }

上面的代碼就輸出了二維數組中的所有元素。

  1. 附:這裡的a[0]卻輸出了hello
  2. int main(void)
  3. {
  4.     char a[2][10] = {"hello", "hi"};
  5.     printf( "%s\n", a[0] );
  6.     //printf( "%s\n", *a );
  7.     //printf( "%s\n", *a + 1 ); 輸出 "ello"
  8.     //printf( "%s\n", *(a + 1) ); 輸出 "hi"
  9.     return 0;
  10. }

而這又是為什麼呢?這裡的 a[0] 仍然是一個位址,它指向的是一個字元串常量,%s 是可以列印位址的,這裡跟 %d 輸出值是不一樣的,a[0] 指向了字元串的第一個字母的位址,一直輸出到 NUL 為止。

繼續閱讀