2.c语言数组

1. 一维数组的创建和初始化

1.1 数组的创建

数组是一组相同类型元素的集合。
数组的创建方式:

type_t arr_name [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小

数组创建的实例:

//代码1
int arr1[10];

//代码2
int count = 10;
int arr2[count];//数组时候可以正常创建?
// 在这个示例中,数组 arr2 的大小是变量 count 的值,因此在运行时确定。在支持C99标准的编译器中,这段代码可以正常编译和运行。

//代码3
char arr3[10];
float arr4[1];
double arr5[20];

注:数组创建,在C99标准之前, [ ] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念。

1.2 数组的初始化

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。

演示代码:

int arr1[10] = {1,2,3};
int arr2[] = {1,2,3,4};
int arr3[5] = {12345}char arr4[3] = {'a',98, 'c'};
char arr5[] = {'a','b','c'};
char arr6[] = "abcdef";

数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定。
但是对于下面的代码要区分,内存中如何分配

char arr1[] = "abc";
char arr2[3] = {'a','b','c'};

这两行代码都涉及字符数组的声明和初始化,但是它们的初始化方式略有不同,因此内存中的分配也会有所区别。

  1. char arr1[] = "abc";

这行代码声明并初始化了一个字符数组 arr1,初始化使用了字符串常量 "abc"。在内存中,该数组被分配了足够的空间来存储字符串 "abc",以及字符串末尾的空字符 '\0'。因此,arr1 的大小将是字符串长度加上一个额外的空字符的大小。通常情况下,编译器会自动计算字符串的长度并分配足够的空间。

内存分配示意图:

+---+---+---+---+
| a | b | c | \0|
+---+---+---+---+
| 97| 98| 99|  0 |
+---+---+---+---+
  arr1
  1. char arr2[3] = {'a','b','c'};

这行代码声明并初始化了一个字符数组 arr2,并显式地提供了初始化的元素。数组的大小被指定为 3,因此只有足够的空间来存储给定的元素。由于没有为数组提供额外的空间来存储空字符 '\0',因此 arr2 不会被视为一个以 null 结尾的字符串。

内存分配示意图:

+---+---+---+
| a | b | c |
+---+---+---+
| 97| 98| 99|
+---+---+---+
  arr2

总结:

  • char arr1[] = "abc"; 会自动在字符串末尾添加一个空字符 '\0',而 arr1 可以作为以 null 结尾的字符串使用。
  • char arr2[3] = {'a','b','c'}; 不会自动添加空字符 '\0',因此 arr2 不会被视为以 null 结尾的字符串。

1.3 一维数组的使用

对于数组的使用我们之前介绍了一个操作符: [ ] ,下标引用操作符。它其实就数组访问的操作符。

演示代码:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };//数组的不完全初始化
	//计算数组的元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
    
	//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
	int i = 0;//做下标
	for (i = 0; i < 10; i++)//这里写10,好不好?
	{
		arr[i] = i;
	}
    
	//输出数组的内容
	for (i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);

这段代码声明了一个包含10个整数的数组 arr,并且将所有元素初始化为0。然后,通过计算数组的总大小除以数组中单个元素的大小,得到了数组的长度。

让我们来逐步解释这段代码:

  1. int arr[10] = { 0 };:这行代码声明了一个名为 arr 的整型数组,有10个元素。数组的所有元素都被初始化为0,这是由初始化列表 { 0 } 实现的。如果初始化列表中提供的元素少于数组的长度,那么剩余的元素将被初始化为0。

  2. int sz = sizeof(arr) / sizeof(arr[0]);:这行代码计算了数组 arr 的长度。sizeof(arr) 返回整个数组 arr 占用的字节数,而 sizeof(arr[0]) 返回数组中第一个元素的大小(通常情况下,这与整个数组的大小相同)。通过将整个数组的大小除以单个元素的大小,可以得到数组中元素的个数。

因此,sz 的值将是数组 arr 的长度,即10。这种计算数组长度的方法是一种常见的做法,可以确保在改变数组大小时代码仍然正确地计算数组的长度。

1.4 一维数组在内存中的存储

探讨数组在内存中的存储。

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; ++i)
	{
		printf("&arr[%d] = %p\n", i, &arr[i]);
	}
	return 0;
}

打印结果:

image-20240320110359704

仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增。
由此可以得出结论:数组在内存中是连续存放的。

image-20240320110451137

2. 二维数组的创建和初始化

2.1 二维数组的创建

//数组创建
int arr[3][4];     // 这是一个三行四列的二维数组
char arr[3][5];
double arr[2][4];

2.2 二维数组的初始化

//数组初始化
int arr[3][4] = {1,2,3,4};     // 1,2,3,4为第一行;其他元素为0
int arr[3][4] = {{1,2},{4,5}}; // 将1,2放在第一行;3,4放在第二行;其他元素为0
int arr[][4] = {{2,3},{4,5}};  //二维数组如果有初始化,行可以省略,列不能省略

2.3 二维数组的使用

二维数组的使用也是通过下标的方式。

#include <stdio.h>
int main()
{
	int arr[3][4] = {0};
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			arr[i][j] = i * 4 + j;
		}
	}
    
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
	}
    
	return 0;
}

2.4 二维数组在内存中的存储

#include <stdio.h>
int main()
{
	int arr[3][4];
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
            // %p 控制符并将一个指针作为参数传递给 printf 函数时,它会打印出指针所指向的内存地址。通常情况下,它会以十六进制的形式打印出指针的值。
			printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
		}
	}
	return 0;
}

image-20240320111629154

通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。

image-20240320111705183

3. 数组越界

数组的下标是有范围限制的。
数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。
所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就
是正确的,
所以程序员写代码时,最好自己做越界的检查。

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		printf("%d\n", arr[i]); //当i等于10的时候,越界访问了
	}
	return 0;
}

二维数组的行和列也可能存在越界。

4. 数组作为函数参数

4.1 冒泡排序函数的错误设计

//方法1:
#include <stdio.h>

// void bubble_sort(int* p)
void bubble_sort(int arr[])
{
    //这样对吗?(此处是错误的)
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

int main()
{
	int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
	bubble_sort(arr);//是否可以正常排序?
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

解析:

在这段代码中,主要问题出现在 bubble_sort 函数内部的 sz 的计算上:

int sz = sizeof(arr)/sizeof(arr[0]);

这里的错误在于 arr 是一个指向整型数组的指针,而不是一个数组,因此 sizeof(arr) 将返回指针的大小,而不是数组的大小。在函数参数中声明一个数组时,其实质是将数组作为指针传递给函数,因此 sizeof(arr) 将返回指针的大小,而不是数组的大小。

要解决这个问题,可以将数组的大小作为额外的参数传递给 bubble_sort 函数,或者使用动态数组,或者使用全局数组。以下是一种修正方法:

#include <stdio.h>

void bubble_sort(int arr[], int sz) {
    int i, j;
    for(i = 0; i < sz - 1; i++) {
        for(j = 0; j < sz - i - 1; j++) {
            if(arr[j] > arr[j + 1]) {
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }
    }
}

int main() {
    int arr[] = {3,1,7,5,8,9,0,2,4,6};
    int sz = sizeof(arr) / sizeof(arr[0]);
    
    bubble_sort(arr, sz);
    
    for(int i = 0; i < sz; i++) {
        printf("%d ", arr[i]);
    }
    
    return 0;
}

在这个修正后的代码中,bubble_sort 函数接受额外的参数 sz,用于传递数组的大小。在 main 函数中,使用 sizeof 操作符计算了数组 arr 的大小,并将其作为参数传递给 bubble_sort 函数。

4.2 数组名是什么?

#include <stdio.h>
int main()
{
    int arr[10] = {1,23,4,5};
    // 数组名arr就相当于首元素地址,即相当于&arr[0]
    printf("%p\n", arr);  
    // &arr[0]是数组首元素的地址
    printf("%p\n", &arr[0]);
    // *arr 是一个指针解引用操作,它指向数组 arr 的第一个元素
    printf("%d\n", *arr);
    // 输出结果
    return 0;
}

数组名确实能表示首元素的地址,但是有2个例外
1.sizeof(数组名),这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址

arr+1 或者 &arr[0]+1  首元素的地址加4个字节;
&arr+1(跳过整个数组 以arr[10]={0}为例 &arr+1表示arr[10]的地址加40字节 )

补充:

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
  2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

作,它指向数组 arr 的第一个元素
printf(“%d\n”, *arr);
// 输出结果
return 0;
}

数组名确实能表示首元素的地址,但是有2个例外
1.sizeof(数组名),这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址

arr+1 或者 &arr[0]+1 首元素的地址加4个字节;
&arr+1(跳过整个数组 以arr[10]={0}为例 &arr+1表示arr[10]的地址加40字节 )


补充:
> 1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
> 2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

除此以上两种情况之外,所有的数组名都表示数组首元素的地址。
  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值