查看原文
其他

【实用】关于数组与指针的总结

正念君 嵌入式大杂烩 2021-01-31

参考:C语言中文网

1

前言


数组与指针有很密切的联系,常见的结合情况有以下三种:

  • 数组指针

  • 指针数组

  • 二维数组指针


2

数组指针


数组指针:指向数组的指针。如:

int arr[] = {0,1,2,3,4};

int *p = arr; 

//也可写作int *p=&arr[0]


也就是说,p,arr,&arr[0]都是指向数组的开头,即第0个元素的地址。


如果一个指针p指向一个数组arr[]的开头,那么p+i为数组第i个元素的地址,即&arr[i],那么*(p+i)为数组第i个元素的值,即arr[i]。


同理,若指针p指向数组的第n个元素,那么p+i为第n+1个元素的地址;不管 p 指向了数组的第几个元素,p+1 总是指向下一个元素,p-1 也总是指向上一个元素。


下面示例证实了这一点:

#include <stdio.h>

int main(void)
{
   int arr[] = {0, 1, 2, 3, 4};
   int *p = &arr[3];  //也可以写作 int *p = arr + 3;

   printf("%d, %d, %d, %d, %d\n",
   *(p-3), *(p-2), *(p-1), *(p), *(p+1) );
   return 0;
}


运行结果为:

0, 1, 2, 3, 4


3

指针数组


指针数组:数组中每个元素都是指针。如:

int a=1,b=2,c=3;

int *arr[3] = {&a,&b,&c};


示例程序:

#include <stdio.h>
int main(void)
{
   int a = 1, b = 2, c = 3;
   //定义一个指针数组
   int *arr[3] = {&a, &b, &c};//也可以不指定长度,直接写作 int *parr[]
   //定义一个指向指针数组的指针
   int **parr = arr;
   printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
   printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));

   return 0;
}


第一个 printf() 语句中,arr[i] 表示获取第 i 个元素的值,该元素是一个指针,还需要在前面增加一个 * 才能取得它指向的数据,也即 *arr[i] 的形式。


第二个 printf() 语句中,parr+i 表示第 i 个元素的地址,*(parr+i) 表示获取第 i 个元素的值(该元素是一个指针),**(parr+i) 表示获取第 i 个元素指向的数据。


指针数组还可以和字符串数组结合使用,请看下面的例子:

#include <stdio.h>
int main(void)
{
   char *str[3] =
 {
       "hello C",
       "hello C++",
       "hello Java"
   };
   printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
   return 0;
}


运行结果为:

hello C

hello C++

hello Java


4

二维数组指针


二维数组指针:指向二维数组的指针。如:

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

int (*p)[4] = a;


a[3][4]表示一个3行4列的二维数组,其所有元素在内存中是连续存储的。

请看如下程序:

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


运行结果为:

a[0][0]=6422216

a[0][1]=6422220

a[0][2]=6422224

a[0][3]=6422228

a[1][0]=6422232

a[1][1]=6422236

a[1][2]=6422240

a[1][3]=6422244

a[2][0]=6422248

a[2][1]=6422252

a[2][2]=6422256

a[2][3]=6422260


可见,每个元素的地址都是相差4个字节,即每个连续在内存中是连续存储的。


按照以上定义可归纳出如下4个结论:

(1)p指向数组a的开头,也即第1行;p+1前进一行,指向第2行。

(2)*(p+1)表示取第2行元素(一整行元素)。

(3)*(p+1)+1表示第2行第2个元素的地址。

(4)*(*(p+1)+1)表示第2行第2个元素的值。


综上4点,可得出如下结论:

a+i == p+i
 *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) 

== *(p[i]+j) == *(*(a+i)+j)

 == *(*(p+i)+j)


以上就是数组与指针常用的三种结合形式,应注意理解并加以区分。


推 荐 阅 读

【常见】getchar()、getche()、getch()的区别?
【知识点】#define与typedef的区别?
【常用】static有几种用法?

【常用】extern怎么用?

【易错】char *str与char str[]的区别?

【提高效率】你应该用复合赋值语句?

【知识点】来看一看volatile关键字

【知识点】C语言变量默认的初值是?

【易错】C语言内存对齐问题

【每日一句】

你所有那些不为人知的努力,都被旁人称之为:幸运。



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存