C++指针解读(4)-- 指针和数组(一维数组)

1、数组及数组的访问

1.1 数组的存储方式

在内存中,数组是一块连续的区域。数组的存储结构有如下特点:

(1)数组中的元素是同质的数据;

(2)索引从0开始;

(3)数组在内存中的存储单元是连续的;

(4)数据元素是按顺序连续存放的;

比如数组:

int a[6] = {1, 2, 3, 3, 5, 6};

它在内存中的存储结构是这样的:

C++指针解读(4)-- 指针和数组(一维数组)_第1张图片

1.2 数组指针

访问数组可以用下标法访问,比如a[0]访问数组的第一个元素;也可以通过指针访问。在C语言中,数组名代表数组首个元素的地址。比如a与&a[0]是等价的。所以,我们可以通过*a访问数组的第1个元素,*(a+1)访问数组的第2个元素,等。

在用数组名时,有几个地方不能把数组名当首地址看:

(1)sizeof(a)求数组空间长度时。这里的a代表整个数组。注意这个sizeof()不是函数,是关键字,用来计算数据在内存中使用的字节数,是在编译时确定的。比如,sizeof(a) = 6*4 = 24个字节。

(2)&a表示取数组a的地址,跟&a[0]是不同的。

a只是代表数组首元素的地址,是指向数组首元素的指针;和指向这个数组的指针不是一码事。在指针变量的定义时我们知道,指针变量包含数据类型和指针名字,所以指向数组的指针的数据类型是数组,其指针值+1就代表地址往下移动 “每个数组元素字节*数组长度” 的字节数。而a+1指针只是往后移动1个数组元素字节。

int a[6] = {1, 2, 3, 3, 5, 6};
int *pi = &a[0];
pi = &a[1]; //可以的
pi = &a; //会报错,因为pi是个int指针,可以指向数组里的元素,但不能指向整个数组

int (*pi2)[6]; //指向包含6个int元素的数组的指针
pi2 = &a; //这么写就可以了

(3)数组赋值的错误方式:

char str[10];
str = "abcd"; //报错

int arr_i[10];
arr_i = { 1, 2, 3 }; //报错

正确的赋值方式:

char str[10];
strcpy(str, "abc");

int arr_i[10];
for (int i = 0; i < 10; i++) {
    arr_i[i] = i;
}

或者在定义的时候初始化:

char str[10] = "abcd";
int arr_i[10] = { 1, 2, 3 };

2、数组指针相关运算

2.1 基础运算规则

假如定义了下面的数组和数组指针:

int a[6] = {1, 2, 3, 3, 5, 6};
int *p1 = &a[0];
int *p2 = &a[2];

(1)p1表示数组的首地址,则p1+i表示数组元素a[i]的地址。

(2)*p1表示数组元素a[0]的值,*(p1+i)表示数组元素a[i]的值。

(3)p2 - 1表示上一个数组元素,即a[1];p2 + 1表示下一个数组元素,即a[3]。

(4)p2 - p1是2个地址之差。

int a[6] = { 1, 2, 3, 3, 5, 6 };
int* p1 = &a[0];
int* p2 = &a[2];

printf("%p\n", p1);
printf("%p\n", p2);

int size1 = (char)p2 - (char)p1; //转成char后的差才是字节数
int size2 = p2 - p1;
printf("size1 = %d, size2 = %d\n", size1, size2);

输出结果如下:

这里需要注意,因为p2、p1是地址,所以减之前要转成char,这样减的差值才是地址字节数。

2.2 数组指针运算应注意的几个问题

int a[6] = {1, 2, 3, 3, 5, 6};
int *p = a;

(1)*p++

从右往左读。因此它等价于*(p++)。++在变量后表示先返回变量的值,然后再+1。比如i++表示先返回i的值,然后i+1。所以*(p++)先返回*p的值,然后指针再加1,指向p+1,即a[2]的位置。

(2)*(p++)和*(++p)

我们知道i++表示先返回i的值,然后i+1;++i表示先i+1,然后返回i的值。所以*(++p)先把指针往下移动1个数组元素,然后再返回这个元素的值,即返回a[2]的值。

(3)++(*p)

从右往左读。先得到*p的值,即a[1]的值。然后把a[1]的值加1。

3、用数组名作函数参数

数组名作函数参数可以写成下面的形式:

func(int arr[], int len)
//或
func(int* parr, int len)

上面2种方式是等价的,另外要记住数组作形状参时,必须同时传入数组的长度,否则可能会造成读取数组越界。这里有人可能会有疑问,不是可以在函数里用sizeof(arr)去获取数组的长度吗?不行的,因为形参int arr[]其实传过来的是实参数组的首地址。所以函数里的sizeof(arr)返回的是指针的长度,在32位系统中是4个字节,64位系统中是8个字节。

3.1

(1)数组表示法

void print(int arr[], int len) {
    for (int i = 0; i < len; i++) {
        //printf("arr[%d] = %d\n", i, *(arr + i)); //这2种打印方法都可以
        printf("arr[%d] = %d\n", i, arr[i]); 
    }
}

int main()
{
    int a[6] = { 1, 2, 3, 3, 5, 6 };
    print(a, 6);

    return 0;
}

(2)指针表示法

void print(int *arr, int len) {
    for (int i = 0; i < len; i++) {
        printf("arr[%d] = %d\n", i, *(arr + i));
        //printf("arr[%d] = %d\n", i, arr[i]); //这2种打印方法都可以
    }
}

你可能感兴趣的:(C++指针解读,c++,算法,数据结构,数组,指针)