数组与指针关系

一、数组指针与指针数组

1. 指针数组:是指一个数组里面装着指针,也即指针数组是一个数组;

定义形式:int *a[10];

说明[]优先级高于*,该定义形式应该理解为:int * (a[10]);括号里面说明a是一个数组,包含了10个元素,括号外面说明每个元素的类型为int *。

2. 数组指针:是指一个指向数组的指针,它其实还是一个指针,只不过是指向数组而已;
定义形式:int (*p)[10]; 其中,由于[]的优先级高于*,所以必须添加(*p).

说明:括号中的*表明 p 是一个指针,该指针变量保存的是一个数组的首地址,它指向一整个数组(),数组的类型为int[10],这正是 a 所包含的每个一维数组的类型。
 

二、指针与数组替换

  1. 数组的声明,如 extern char a[];不能改写成指针形式。当然,数组的定义更不能。

  2. 函数的参数,如 func(char a[]),可以改写成指针的形式。

  3. 表达式中的使用,如 c=a[i];,可以自行选择使用数组形式或指针形式。

注意:以下情况,数组名和指针不同,仍代表整个数组

  1. 数组名作为 sizeof的操作数,如 sizeof(a), 求得的是整个数组的大小(整个数组有多少字节)
  2. 用 & 符号取数组名的地址(如 int a[100];, 则 &a代表 int (*)[100], 但数值上仍等同于 &a[0], 而大小却不同 )
  3. 数组是一个字符串(或宽字符串)常量初始值。

三、多维数组与指针关系

int apricot[2][3][5];

可以使用下列任何一种方法为它在内存中定位:

int (*p)[3][5] = apricot;

  • p是一个指针,它指向一个二维数组
  • 这个二维数组第一维是3,第二维是5
  • p所指向的这个二维数组就是apricot这个三维数组中的第一个二维数组
  • apricot 是一个三维数组的名字,就相当于一个指向二维数组的指针
  • 这正如一个一维数组的名字,就相当于一个指向数组元素的指针

int (*r)[5] = apricot[i];

  • r是一个指针,它指向一个一维数组
  • 这个一维数组包含了5个int型数字
  • r所指向的这个一维数组就是apricot[i]中的第一个一维数组

int *t = apricot[i][j];

  • t本身的含义是一个 int 型指针
  • t此时仍表示它所指向的是一个int型数字的地址
  • apricot[i][j]是一个一维数组的名字,因此相当于一个int型指针

四、数组与指针与形参、实参的关系

主要规则如下:

  • 若实参为数组的数组,如 char c[8][10], 则形参为数组指针, 如 char (*)[10]
  • 若实参为指针数组,如 char *c[15], 则形参为 指针的指针, 如 char **c
  • 若实参为数组指针或指针的指针,则形参保持不变(即保持和实参形式一致),例如:
#include <stdio.h>

// s1是第一维的长度;
// 第二维的长度已经在第一个参数指定
void print2D(int (*p2D)[3], int s1)
{
    int i=0, j=0;
    
    for (i=0; i<s1; i++) {
        for (j=0; j<3; j++) {
            printf("%d ", p2D[i][j]);
        }
        printf("\n");
    }
}

void print2DW3(int array[][3], int s1)
{
    int i=0, j=0;
    
    for (i=0; i<s1; i++) {
        for (j=0; j<3; j++) {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    int array2D[2][3] = {
        {1, 2, 3},
        {4, 5, 6}
    };
    
    // way-1
    int (*p2D)[3] = array2D;
    print2D(p2D, 2);
    
    // way-2
    // 二维数组的名字,就相当于一个指向一维数组的指针
    print2D(array2D, 2);
    
    // way-3
    print2DW3(array2D, 2);

    return 0;
}

补充:

定义指针时,编译器并不为指针所指向的对象分配空间,它只分配指针本身的空间,除非在定义时同时赋给指针一个字符串常量进行初始化.例如,下面的定义创建了一个字符串常量(为其分配了内存):

char *p = "breadfruit";

注意只有对字符串常量才是如此.不能期望为浮点数之类的常量分配空间,如:(只为字符串分配内存)

float *pip = 3.141; /* 错误!无法通过编译. */

指针初始化为字符串,其内容不能修改;数组字符串是可以修改内容的。

下面3个函数都接收同样类型的参数,3个变量apricot、p、*q都匹配所有3个函数的参数声明。

my_function_1( int fruit[2][3][5]) { ; }

my_function_1( int fruit[][3][5]) { ; }

my_function_1( int (*fruit)[3][5]) { ; }

int apricot[2][3][5];

int (*p)[3][5] = apricot;

int (*q) [2][3][5] = &apricot;

​NULL可以被定义为(void *)0,而NUL可以被定义为'/0'。

  • 9
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值