C/C++基础 -- 指针与数组、字符串(包含二维数组)

C/C++基础 — 指针与数组、字符串

本博文由 西北工业大学MOOC 总结而来,以备以后回顾。
此次二维数组为自己增加的内容,如有错误欢迎留言指正

1、一维数组和指针

1.1、一维数组的地址

  数组由若干元素组成,每个元素都有相应的地址,通过取址运算符(&)可以得到每个元素的地址。
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》
  C++规定,数组名既代表数组本身,又代表整个数组的地址,还是数组首元素的地址。即a与a的第0个元素的地址&a[0]相同。例如,
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》
  数组名是一个指针常量,因为不能出现在左值和某些算术运算中,例如:《C/C++基础 -- 指针与数组、字符串(包含二维数组)》

1.2、指向一维数组的指针变量

  定义指针时,用数组名初始化指针,即可将指针指向一维数组。指针的指向类型应和数组元素类型一致。例如:《C/C++基础 -- 指针与数组、字符串(包含二维数组)》

1.3、通过指针访问一维数组元素

  由于数组元素的地址是规律性增加的,更具指针算术运算规则,可以利用指针及其运算来访问数组元素。
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》
  访问一维数组元素有以下四种方法:
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》

2、二维数组和指针

2.1、二维数组的地址

  假如有一个二维数组:

int a[3][4] = { { 1, 3, 5, 7}, { 9, 11, 13, 15}, { 17, 19, 21, 23}};

  其中,a 是二维数组名。a 数组包含 3 行,即 3 个行元素:a[0],a[1],a[2]。每个行元素都可以看成含有 4 个元素的一维数组。而且 C 语言规定,a[0]、a[1]、a[2]分别是这三个一维数组的数组名。如下所示:
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》
  a[0]、a[1]、a[2] 既然是一维数组名,一维数组的数组名表示的就是数组第一个元素的地址,所以 a[0] 表示的就是元素 a[0][0] 的地址,即

a[0] == &a[0][0];
a[1] == &a[1][0];
a[2] == &a[2][0];

  所以二维数组 a[M][N] 中,a[i] 表示的就是元素 a[i][0] 的地址,即

a[i] == &a[i][0];

  则 a[i]+j 就表示元素 a[i][j] 的地址,即:

a[i]+j == &a[i][j];

  同时由一维数组 a[i] 和 *(a+i) 等价,引申至二维有:

*(a+i)+j == &a[i][j];

二维数组的首地址和数组名

  二维数组就是一维数组,二维数组 a[3][4] 就是有三个元素 a[0]、a[1]、a[2] 的一维数组,所以二维数组 a[3][4] 的第一个元素不是 a[0][0],而是 a[0] (第一行元素的地址),所以数组名 a 表示的不是元素 a[0][0] 的地址,而是 a[0] 的地址,即:

a == &a[0];		//数组名代表数组第一行元素a[0]的地址

而 a[0] 又是 a[0][0] 的地址,即:

a[0] == &a[0][0];

则二维数组名 a 和 元素名 a[0][0] 的关系是:

a == &(&a[0][0]);		//数组名代表数组第一行元素a[0]的地址

  二维数组的空间在内存中也是连续的地址。对于内存而言,没有维度而言,内存是一维的,内存里面不分行也不分列,元素都是按顺序一个一个往后排的,所以二维数组中的每一个元素在内存中的地址都是连续的。如下:
定义一个二维数组:

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

按行输出为:

1  2  3  4
5  6  7  8
9  10 11 12

其元素的地址输出为:

0X18FF18 0X18FF1C 0X18FF20 0X18FF24
0X18FF28 0X18FF2C 0X18FF30 0X18FF34
0X18FF38 0X18FF3C 0X18FF40 0X18FF44

可以看出二维数组元素的地址在内存中是连续存在的。

2.2、指向二维数组的指针变量

  前面提到过,二维数组是由一行一行的一维数组组成的,如 a[0]、a[1],a[2];同时也是由一个一个的单独的元素组成的,如 a[0][0]、a[1][1]、a[2][2]。所以指向二维数组的变量可以有两种形式:
1)行指针:(常用)
行指针的定义如下,其指向的是二维数组的第0行。形式如下:

指针类型 (*指针名称)[数组列数] = 数组名/数组第0行元素地址;
int a[M][N] = { .......};
int (*p)[N] = a;    //其中N是二维数组a[M][N]的列数, 是一个数字。//**数组长度不能定义成变量
int (*p)[N] = &a[0];//a == &a[0];
	//***************注意与指针数组作区别,int *p[4] 为指针数组,
	// 其中包含四个int型指针,即p[0],p[1],p[2],p[3]都是int型指针,其中存储的都是地址值

2)列指针:
列指针指向二维数组的第0个元素,其在形式上与指向单一对象的指针没有区别。形式如下:

指针类型 *指针名称 = 数组第[0][0]元素;
int a[M][N] = { .......};
int *p = &a[0][0];	//指向二维数组第0行第0列的元素

  注意这两种指针都是一个指针,应与指针数组做区别(由多个指针元素组成的数组)。且指向二维数组的两种指针不能弄混,是因为二维数组的组成既是由行元素组成,也是由单个元素组成。行指针只能指向数组的行(一般指向第0行),其定义必须包含数组的列长度;列指针只能指向某一个元素,其相当于一个指向单独对象的指针。

2.3、通过指针访问二维数组的元素

1)行指针:(常用)
  定义一个二维数组和指向该数组的指针:

int a[3][4] = {  { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9, 10, 11, 12} };
int (*p)[4] = a;	//将指针指向二维数组a的首地址

则有如下的取值方式:

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

  括号的运算优先级最高,所以最先运算 p+i,将指针指向第 i 行,再运算 * 号解引用得到第 i 行的首地址 &a[i],再运算 &a[i]+j,将指针指向第 i 行 第 j 列的元素的地址&a[i][j],再运算 * 号解引用得到元素的值 a[i][j]。
  同理,还有其他取值方式:

*(*p) == *(a[0]) == *(&a[0][0]) == a[0][0];	//value = 1
*(*p+1) == *(a[0]+1) == *(&a[0][1]) == a[0][1];//value = 2
*(*(p+1)) == *(a[0+1]) == *(&a[1][0]) == a[1][0];//value = 5
*(*(p+1)+2) == *(a[1]+2) == *(&a[1][2]) == a[1][2];//value = 7

2)列指针:
  列指针的实质是一个指向单独元素的指针,利用二维数组在存储空间上的连续性,也可对通过相应操作取得相应的值。举例如下:

# include <stdio.h>
int main(void)
{ 
    int a[3][4] = {  { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9, 10, 11, 12} };
    int i, j;
    int *p = &a[0][0];  //把a[0][0]的地址赋给指针变量p
    for (i=0; i<3; ++i)
    { 
        for (j=0; j<4; ++j)
        { 
            printf("%-2d\x20", *(p+i*4+j));//由于存储空间是一维的,所以只能用i*4表示换行
        }
        printf("\n");
    }
    return 0;
}

3、字符串和指针(char型指针,c语言描述)

  字符串指针的操作和数组指针的操作是相同的,所以本文在此也加入字符串指针的相关内容。
  可以利用一个字符型的指针处理字符串,其过程与通过指针访问数组元素相同。使用指针可以简化字符串的处理,是处理字符串常用的方法。

3.1、字符串指针的定义

  c++允许定义一个字符指针,初始化时指向一个字符串常量,一般形式为:

*推荐)
char str[20] = "C Language";
char *p_str = str;	//指针指向字符串数组的首地址

或定义时直接赋值
char *p_str = "C Language";char *p_str;
*p_str = "C Language"

  以上的方法定义和初始化的指针,都是指向字符串的首地址。

3.2、通过指针访问字符串

1)基本访问形式
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》
2)通过字符指针遍历字符串
  一般使用while循环来遍历字符串,形式有两种:
①while (*p != ‘\0’){ 操作内容 };
②while (*p){ 操作内容 };
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》

3.3、指针访问二维字符串

  二维字符串在形式上和二维数组相同,其操作方式也与指向二维数组的指针相同,只是在每一个字符串的末尾都以 ‘\0’ 结束,在使用时需要加以注意,多用判断方式越界操作。如图所示:
《C/C++基础 -- 指针与数组、字符串(包含二维数组)》

    原文作者:不世峰兄
    原文地址: https://blog.csdn.net/weixin_43569276/article/details/100573292
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞