C/C++ 数组、指针与函数

数组与指针

  • 数组名数组第一个元素的地址
int ar[10];
int* p = ar;
p == &ar[0];
*p == ar[0];
  • 多维数组可看做一维数组,其每个元素也是一个数组
int ar[4][5];
int (*p)[5] = ar;
int* r = ar[0];

p == &ar[0];
*p == ar[0];

r == *p;
r == &ar[0][0];
*r == **p == ar[0][0];
  • 使用数组表示法 ar[i]ar[i][j] 和使用指针表示法 *(ar+i)*((ar+i)+j) 两种方法等价。
    • 但是只有当 ar 是指针变量时, 才能使用 ar++ 这样的表达式
#include<stdio.h>
int main(void)
{
    int ar[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
    // 数组表示法
    printf("ar[2][1] = %d\n",ar[2][1]);
    // 指针表示法
    printf("*(*(ar + 2)+1) = %d\n", *(*(ar + 2) + 1));
    // 两者混用
    printf("*(ar[2]+1) = %d\n", *(ar[2] + 1));
    printf("(*(ar+2))[1] = %d\n", (* (ar + 2))[1]);
}

输出:

  • 数组元素的存储方式是顺序存储,即相邻元素的存储地址也是相邻的。
#include<stdio.h>
int main(void)
{
    int ar[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
    // 指向含四个数组的元素的指针
    printf("ar = %p\n", ar);
    // +1 移动 4*sizeof(int) = 16 个字节 
    printf("ar + 1 = %p\n", ar +1 );

    // 指向 int 类型的指针
    printf("*ar = %p\n", *ar);
    // +1 移动 1*sizeof(int) = 4 个字节 
    printf("*ar + 1 = %p\n", *ar + 1);

    // 基于顺序存储的特性来遍历数组元素:
    int* p = *ar;// p = &ar[0][0]
    int rows = 3;
    int cols = 4;
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            printf("%d\t", *(p + i * cols + j));
        }
        printf("\n");
    }
}

输出:

数组与函数

一维数组与函数

函数要处理一维数组一般有两种方式:

  • 数组首元素的地址或指针,和数组的长度作为函数的参数
  • 要处理的数组元素的起始指针和终止指针作为函数参数,终止指针一般指向要处理的最后一个数组元素的下一个位置。
/// 第一种方法
/// @param	ar	数组名、数组首地址、或指向数组第一个元素的指针
/// 数组长度
void somefunction(int ar[], int len);
void somefunction(int* ar, int len);
// 这里 [] 表示参数类型为指向 int 类型的指针,等价于 int*
// 但只在在声明形式参数时是等价的。
void somefunction(int [],int);
void somefunction(int* ,int);

void somefunction(int ar[], int len)
{
    for(int i; i < len; i++)
    {
        printf("%d\t",ar[i]);
    }
}


/// 第二种方法
/// @param	begin	指向起始元素的指针
/// @param	end	指向最后一个元素的后一个元素
void somefunction(int* begin, int* end);
void somefunction(int*, int*);
// 这里 [] 表示参数类型为指向 int 类型的指针,等价于 int*
// 但只在在声明形式参数时是等价的。
void somefunction(int[], int[]);

void somefunction(int* begin, int* end)
{
    int *p;
    while(p < end)
    {
        printf("%d\t",*(p++));
    }
}

多维数组与函数

函数处理多维数组的方式与一维数组类似,多维数组可看做一维数组,其每个元素也是一个数组。

/// 对于一维数组
int ar[6];
int* p = ar;// 类型为 int*,+1移动一个 sizeof(int)

/// 对于二维数组
int ar2d[3][4];
int (*p)[4] = ar;// 类型为 int(*)[4],+1移动一个sizeof(int[4])= 4*sizeof(int)

因此,对于多维数组,也可以用传递一个指针和一个长度的方法,指针指向数组的首元素,等于数组名,对于二维数组,长度即是二维数组的行数。

局限性:由于一个有效的指针必须知道其指向的对象的大小,因此,对于多维数组,在其形参声明中必须指定数组除第一个维度外其他维度的大小。对于二维数组来说,必须指明二维数组的列数,因此,用这种方法,函数只能处理列数固定的二维数组,要想处理其他列数的二维数组,必须再写一个函数。

void somefunction(int (*ar)[4],int rows);
void somefunction(int (*)[4],int );

void somefunction(int (*ar)[4],int rows)
{
    for(int i = 0; i < rows; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            printf("%d\t",ar[i][j]);
        }
        printf("\n");
    }
}

如何处理任意大小的二维数组 ?

c 的方法

1. VLA

C99 新增的变长度数组(variable-length array, VLA),允许使用变量表示数组的维数。

注意:变长数组不能改变大小,这里的“变”指的是: 在创建数组时, 可以使用变量指定数组的维度。

int sum2d(int rows, int cols, int ar[rows][cols]);

/// 求二维数组所有元素之和的函数
/// @param	rows	数组行数
/// @param	cols	数组列数
/// @param	ar	变长度数组,其尺寸由变量 rows 和 cols 定义
/// @return	返回二维数组所有元素之和
int sum2d(int rows, int cols, int ar[rows][cols])
{ 
    int r;
    int c;
    int tot = 0;
    for (r = 0; r < rows; r++)
        for (c = 0; c < cols; c++)
            tot += ar[r][c];
    return tot;
}

前两个形参(rowscols ) 用作第 3 个形参二维数组 ar 的两个维度。因为 ar 的声明要使用 rowscols, 所以在形参列表中必须在声明 ar 之前先声明这两个形参。

(13 封私信 / 80 条消息) 哪些C语言编译器支持VLA(变长数组)? - 知乎 (zhihu.com)

2. 基于顺序存储的特性

数组元素的存储方式是顺序存储,即相邻元素的存储地址也是相邻的,对于二维数组,它的相邻每行的存储地址都是相邻的,而每行又是顺序存储的,所以,相邻每行首尾相连可以看做一个大的一维数组,只需要知道这个一维数组第一个数据元素的地址 int* ar即可确定任意位置的元素,如第 i 行第 j 列的元素为:*(ar+i*cols+j)

int sum2d(int rows, int cols, int* ar);

/// 求二维数组所有元素之和的函数
/// @param	rows	数组行数
/// @param	cols	数组列数
/// @param	ar	二维数组第一个元素的地址
/// @return	返回二维数组所有元素之和
int sum2d(int rows, int cols, int* ar)
{ 
    int r;
    int c;
    int tot = 0;
    for (r = 0; r < rows; r++)
        for (c = 0; c < cols; c++)
            tot += ar[r*cols+c];
    return tot;
}
3. 使用指针数组

创建一个指针数组,让其每个元素都是指向二维数组每行的首元素。

int sum2d(int rows, int cols, int* ar[]);

/// 求二维数组所有元素之和的函数
/// @param	rows	数组行数
/// @param	cols	数组列数
/// @param	ar	指针数组,其每个元素都是一个指针,指向二维数组每行的首元素
/// @return	返回二维数组所有元素之和
int sum2d(int rows, int cols, int* ar[])
{ 
    int r;
    int c;
    int tot = 0;
    for (r = 0; r < rows; r++)
        for (c = 0; c < cols; c++)
            tot += ar[r][c];
    return tot;
}

C++ 的方法

使用 vector

  • 二维数组的声明方式:
// 使用初始化列表
// vector<vector<int>> 中每个元素都是 vector<int> ,表示二维数组的每行。
vector<vector<int>> arr1{ {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13,14,15,16} };

// 使用 push_back();
vector<vector<int>> arr2;
for (int i = 0; i < 4; i++)
{
    vector<int> temp{ i*4 + 1, i*4 + 2, i*4 + 3, i*4 + 4 };
    arr2.push_back(temp);
}
int sum2d(vector<vector<int>> arr)
{
	int tot = 0;
	for (auto& e : arr)
		for (auto& c : e)
			tot += c;
	return tot;
}
posted @   起司头_棕裤裤  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示