当前位置: 首页 > news >正文

17.C语言数组

一维数组

在 C 语言里,一维数组指针指的是指向一维数组的指针。它和普通指针不同,普通指针指向单个变量,而一维数组指针指向的是一整个一维数组。一维数组指针存储的是数组的起始地址,并且它的类型和所指向的数组类型相匹配。

声明与初始化

声明一维数组指针的一般格式为:

数据类型 (*指针变量名)[数组长度];

这里的括号不能省略,因为[]的优先级比*高,若不使用括号,声明的就会是一个指针数组。下面是具体的声明和初始化示例:

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int (*ptr)[5] = &arr;  // 声明并初始化一个指向包含5个int元素的数组的指针
    return 0;
}

在上述代码中,ptr 是一个指向包含 5 个 int 类型元素的数组的指针,通过 &arr 把数组 arr 的地址赋给了 ptr

数组本质上不是一个指针,我们可以通过sizeof进行查看

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

void array_test01() {
	int array[5] = {1,2,3,4,5};

	//一维数组是不是指针?
	printf("array siof: %d\n",sizeof(array));
}


int main() {
	array_test01();
	return EXIT_SUCCESS;
}

运行结果

数组赋值给指针

我们看以下案例:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

void array_test01() {
	int array[5] = {1,2,3,4,5};

	int* p = NULL;
	p = &array;
	printf("array index: %d\n", *(p+0));
}

int main() {
	array_test01();
	return EXIT_SUCCESS;
}

运行结果

从提示来看,两者赋值是不支持的。两者的的指针其实不是一个等价指针,可以看下面警告,间接级别不同。原因是两者之间的步长并不是等价。

数组的步长

void array_test02() {
	int array[5] = { 1,2,3,4,5 };

	printf("array index: %d\n",&array);
	printf("array index: %d\n",&array + 1);
}

int main() {
	array_test02();
	return EXIT_SUCCESS;
}

从&array+1后直接就跳转到了最后一位的地址。如果是数组取地址的话,取的是整个数组的指针,直接跳转,会跳转到最后

向以下案例就属于等价的。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

void array_test01() {
	int array[5] = {1,2,3,4,5};
	int* p = array;
	printf("array index: %d\n", *(p+0));
}

int main() {
	array_test01();
	return EXIT_SUCCESS;
}

指针常量

指针的指向是不可修改的,但是可以修改指针内部元素

指针放负数,原理

我们的数组是可以放入负数的。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"


void array_test01() {
	int array[5] = {1,2,3,4,5};
	int* p = array;
	p = p + 3;
	printf("array: %d\n", p[-1]);
}

int main() {
	array_test01();
	return EXIT_SUCCESS;
}

运行结果

逻辑

首先当前p的偏移位置在第3位,然后,p[-1] 就是第2 。 其实是等价的

定义一个数组的指针

方式1

直接通过数组赋地址给指针,对数组名称取地址,获取的是指针步长,是整个数组的长

void array_test01() {
	int array[5] = {1,2,3,4,5};

	int* p = &array; //这种方式并不是数组指针,对数组名称取地址,获取的是指针步长,是整个数组的长度
}

如果需要定义一个数组指针,首先定义出数组的类型,在通过类型创建数组的指针。

void array_test01() {
	int array[5] = {1,2,3,4,5};

	typedef int(ARRAY_TYPE)[5]; //ARRAY_TYPE是一个数据类型,代表有5个int类型的数组元素

	ARRAY_TYPE *p = &array;

	for (int i = 0; i < 5;i++) {
		//首先是p的地址,如果不把p解引用,那会打印的是地址
		printf("%d\n",(*p)[i]);
	}
}

方式2

先定义数组指针的类型,在创建数组指针的变量

void array_test01() {
	int array[5] = {1,2,3,4,5};

	typedef int(*ARRAY_TYPE)[5]; //先定义数组指针的类型,在创建数组指针的变量

	ARRAY_TYPE p = &array;

	for (int i = 0; i < 5;i++) {
		//首先是p的地址,如果不把p解引用,那会打印的是地址
		printf("%d\n",(*p)[i]);
	}
}

与上面方法有所不同,定义规则直接就变了,直接一步到位。

方式3

直接创建数组指针变量

void array_test01() {
	int array[5] = {1,2,3,4,5};

	int (*p)[5] = &array; // 直接创建数组指针变量

	for (int i = 0; i < 5;i++) {
		//首先是p的地址,如果不把p解引用,那会打印的是地址
		printf("%d\n",(*p)[i]);
	}
}

案例

案例1

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

void printf_array(int arr[],int len) {// int arr[],等价与int * arr
	for (int i = 0; i < len; i++) {
		printf("%d\n",arr[i]);  //给人看
		//printf("%d\n",*(arr+i));//给机器看

	}
}

void array_test01() {
	int array[5] = {1,2,3,4,5};

	int arr_len = sizeof(array) / sizeof(array[0]);
	printf_array(array,arr_len);
}

int main() {
	array_test01();
	return EXIT_SUCCESS;
}

案例2

借助数组指针,可以通过偏移和间接引用操作符来访问数组元素。

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int (*ptr)[5] = &arr;
    // 访问数组的第三个元素
    printf("数组的第三个元素是: %d\n", (*ptr)[2]);
    return 0;
}

在这个例子中,(*ptr) 先对指针 ptr 进行解引用,得到数组本身,然后 [2] 访问数组的第三个元素(下标从 0 开始)。

案例3

一维数组指针能够作为函数参数传递,这样可以在函数内部对数组进行操作。

#include <stdio.h>

// 函数接收一个指向包含5个int元素的数组的指针
void printArray(int (*ptr)[5]) {
    for (int i = 0; i < 5; i++) {
        printf("%d ", (*ptr)[i]);
    }
    printf("\n");
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int (*ptr)[5] = &arr;
    printArray(ptr);
    return 0;
}

在上述代码中,printArray 函数接收一个指向包含 5 个 int 元素的数组的指针作为参数,在函数内部通过该指针访问数组元素并打印。

案例4

在处理二维数组时,可利用一维数组指针来遍历二维数组的每一行。

#include <stdio.h>

int main() {
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    // 声明一个指向包含4个int元素的数组的指针
    int (*ptr)[4];
    for (ptr = arr; ptr < arr + 3; ptr++) {
        for (int i = 0; i < 4; i++) {
            printf("%d ", (*ptr)[i]);
        }
        printf("\n");
    }
    return 0;
}

在这个例子中,ptr 是一个指向包含 4 个 int 元素的数组的指针。外层循环让 ptr 依次指向二维数组的每一行,内层循环遍历当前行的每个元素。

二维数组

在 C 语言中,二维数组指针是指向二维数组的指针。二维数组在内存中是按行优先的顺序连续存储的,二维数组指针可以用来指向这个连续的内存块,并且可以方便地对二维数组进行操作。

从本质上来说,二维数组指针指向的是二维数组的一行,它存储的是二维数组某一行的起始地址

声明二维数组指针

声明二维数组指针的一般形式为:

数据类型 (*指针变量名)[列数];

这里的括号是必需的,因为[]的优先级高于*,不加括号就会声明成指针数组。例如,声明一个指向包含 3 个int类型元素的数组的指针:

int (*ptr)[3];

定义二维数组

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

void array_test01() {
	//格式1
	int array1[3][3] = { 
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};

	//格式2
	int array2[3][3] = {1,2,3,4,5,6,7,8,9};

	//格式3
	int array3[][3] = {1,2,3,4,5,6,7,8,9};
}

int main() {
	array_test01();
	return EXIT_SUCCESS;
}

二维数组指针

#include "stdio.h"
#include "stdlib.h"
#include "string.h"


void array_test01() {

	int array[3][3] = { 
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};

	int (*p)[3] = array;  //二维数组名称 指向 第一个一维数组的指针

	//特殊情况
	printf("sizeof: %d",sizeof(array));  //9个 int类型,输出36

	//创建二维数组指针
	int (*p2)[3][3] = &array;

}

int main() {
	array_test01();
	return EXIT_SUCCESS;
}

指向二维数组并访问元素

#include <stdio.h>

int main() {
    int arr[2][3] = {
        {1, 2, 3},
        {4, 5, 6}
    };
    // 声明并初始化二维数组指针
    int (*ptr)[3] = arr; 

    // 访问第一行第二列的元素
    printf("第一行第二列的元素: %d\n", ptr[0][1]);
    // 另一种访问方式
    printf("第一行第二列的元素: %d\n", *(*(ptr + 0) + 1));

    return 0;
}

解释

  • int (*ptr)[3] = arr;:这里arr代表二维数组首行的地址,将其赋值给ptrptr就指向了二维数组的第一行。
  • ptr[0][1]ptr[0]表示第一行的首地址,再加上偏移量1就访问到第一行第二列的元素。
  • *(*(ptr + 0) + 1)ptr + 0指向第一行,*(ptr + 0)得到第一行首地址,*(ptr + 0) + 1得到第一行第二列元素的地址,最后再解引用就得到该元素的值。

二维数组输出

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

//以下三种方式都是等价的
//void arrayPrintf(int arr[3][3],int row,int col) {
//void arrayPrintf(int arr[][3],int row,int col) {
void arrayPrintf(int (*arr)[3], int row, int col) {
	for (size_t i = 0; i < row; i++)
	{
		for (size_t j = 0; j < col; j++)
		{
			//printf("%d ",arr[i][j]);  //给人看
			printf("%d ",*(*(arr + i)+j));  //机器看
		}
		printf("\n");
	}
}

void array_test01() {

	int array[3][3] = { 
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};
	arrayPrintf(array, 3, 3);
}

int main() {
	array_test01();
	return EXIT_SUCCESS;
}

输出结果

动态分配二维数组并使用指针操作

#include <stdio.h>
#include <stdlib.h>

int main() {
    int rows = 2;
    int cols = 3;
    // 动态分配二维数组
    int (*arr)[3] = (int (*)[3])malloc(rows * sizeof(*arr));

    if (arr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 初始化二维数组
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            arr[i][j] = i * cols + j;
        }
    }

    // 打印二维数组
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }

    // 释放内存
    free(arr);

    return 0;
}
  • int (*arr)[3] = (int (*)[3])malloc(rows * sizeof(*arr));:使用malloc函数动态分配了一个包含rows行、cols列的二维数组。sizeof(*arr)表示一行的大小。
  • 之后通过双重循环对二维数组进行初始化和打印操作。
  • 最后使用free(arr)释放动态分配的内存,避免内存泄漏。

相关文章:

  • 常见的响应头信息
  • Pinia的安装,使用,与情景教学
  • Excel 使用技巧:excel 合并不同列内容; excel 将公式转化为文本
  • 《嫦娥的月球物联网》
  • Day 4 系统总线(2)
  • ubuntu开发mcu环境
  • 基于kubernetes技术实现蓝绿部署(企业实战)
  • Java音频和录音合成 实战demo
  • Linux 部署 rocketmq centos7
  • 读一本书,骑行万里路:与维乐 Angel Rise+骑行看世界
  • ai画图flux depth景深控制空间位置生图
  • 软件工程之软件测试(单元测试、集成测试、系统测试)
  • 06.AI搭建preparationの(transformers02)bertmodel实现bert-base-chinese的编码
  • 论文阅读笔记——PointVLA: Injecting the 3D World into Vision-Language-Action Models
  • DevEco Studio编辑器的使用-代码code Linter检查
  • 【博客】使用GithubAction自动同步obisidian和hexo仓库
  • QTableView开发入门
  • @DeclareParents 注解实现接口功能增强:Spring中通过接口引入实现功能增强的完整示例
  • 保存预测图像时出现的文件名错误
  • Python----机器学习(KNN:决策边界,决策边界计算,交叉验证步骤)
  • 建设集团企业网站/竞价推广出价多少合适
  • 设计一个校园网方案/牛排seo
  • 怎么制作网站app/游戏优化大师下载安装
  • 网站建设 工作方案/ip域名查询地址
  • 广州企业模板建站/网络推广优化工具
  • 如何注册自己的网站/精准客户运营推广