[编程神域 C语言浮游塔 第③期]数组

本文详细介绍了C语言中数组的基础知识,包括一维数组的定义、初始化和引用,以及二维数组和多维数组的概念。文章还探讨了一维数组作为函数参数的使用,字符数组的定义、初始化和输入输出方法。此外,提到了数组在实际项目中的应用,如学生成绩管理系统。
摘要由CSDN通过智能技术生成

6e974bef98b92ae19d2cc59d3261b434.png


前言

嗨嗨,这里是枫枫。

没想到我们的专栏能迎来第三期,先来庆祝一下。

 本期的内容主要是设计到一维数组以及字符串数组,其中会夹杂些其他的有关内容,例如一维数组作为函数参数等等。

下面,先给大家讲讲什么是数组。

数组是一种高效的数据组织方式,几乎所有的高级程序设计语言都支持数组。

所谓数组,就是指相同类型数据的一个有序集合。

这些数据有一个共同的名字——数组名(必须是合法的标识符)。

集合中的元素称为——数组元素。

集合中元素的位置信息被称为——下标,在引用某个元素时只要给出数组名和该元素的下标即可。

数组元素类型任意,可以是基本类型中的字符型、整型、浮点型等,

也可以是指针,或结构体、共用体等构造类型

因为每个元素的类型均相同,所以它们占用内存中连续的存储单元,其中第一个数组元素的内存地址是数组所占内存块的首地址,数组名就代表数组的首地址

它是一个常量。可表示为:&a[0]=a。

数组在使用原则上与普通变量一致,即先定义后使用,先定义的目的是先让计算机准备好内存空间,将来存放数据。数组的定义就是给出数组名、元素类型和元素个数3个方面的信息。

好了,基本的介绍就到这里,下面让我们进入正题吧。

那么,新的“游戏”,开始吧!

Link Start!

目录

浮游塔第21层:一维数组的定义

浮游塔第22层:一维数组的初始化

浮游塔第23层:一维数组元素的引用

浮游塔第24层:二维数组基础

浮游塔第25层:多维数组基础

浮游塔第26层:一维数组作为函数参数

浮游塔第27层:字符数组的定义

浮游塔第28层:字符数组的初始化

 浮游塔第29层:字符数组的输入输出

 浮游塔第30层:字符数组的引用

浮游塔隐藏层:数组的应用

后记


浮游塔第21层:一维数组的定义

(最基本、最简单的数组)

一维数组是最基本也是最简单的数组,在平常的学习种,也是碰得最多的数组。

其定义的一般格式为:元素类型标识符  数组名[长度(即元素个数)];

例如:int a[10];或char ch[9];

注:长度必须是整型常量整型常量表达式,因为在C语言中,数组不能动态定义。

其实数组的定义,就是开辟出内存空间用来存放数组元素,至于开辟出多大的空间,则是由数组长度数组类型决定的。

数组长度就是再定义时,数组元素的个数;

数组类型决定了每个数据元素所占内存的字节数。

二者的乘积等于数组占内存的总字节数

总字节数=数组长度(或元素个数)*sizeof(数组类型)


浮游塔第22层:一维数组的初始化

(数组的初始化=给数组元素赋值)

一维数组未进行初始化的数组如果是局部的,其各个元素的值是不确定的;

如果是全局的或者静态的,各元素的值默认为零值。

其一般格式为:元素类型标识符 数组名[元素个数]={数据1,数据2,···,数据n};

例:

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

在初始化的过程中,可以省略元素个数的多少,

例如:int a[ ]={1,2,3,4,5,6};

若整个数组都没有进行初始化,则每个元素都会被赋为乱码。

也可以部分元素连续初始化:

例如:int a[6]={1,2,3};数组a的前三个元素被分别赋值为1,2,3,而后三个元素则自动赋值为0,即初始化时给出的数据不足,其余的元素会被自动赋值为0。

如果是字符数组,则会被赋值到字符’\0’。

①:全部赋初值

例如:int arr[5] = {90, 80, 95, 85, 75};

arr[0]

arr[1]

arr[2]

arr[3]

arr[4]

90

80

95

85

75

注意:

1、初值的个数不能大于数组的长度,否则会产生运行时错误。

例如:int a[2]={1,2,3,4};

2、每个初值的类型最好与数组的类型一致,精度高的数组可以赋以精度低的元素。

例如:double型的数组可以包含Int型的元素,但精度低的数组不能赋以精度高的元素,例如int型的数组不能包含double型的元素。

②:部分赋初值

例如:int arr[5] = {90, 80};

arr[0]

arr[1]

arr[2]

arr[3]

arr[4]

90

80

0

0

0

注意:

  • 未赋值的元素都为0。
  • 实际开发中经常使用部分赋值的方式进行
#define ARR_SIZE 5
int c_score[ARR_SIZE]={0};  //可以表示元素全为0,因为只有第一个元素赋以0 ,而后面的元素自动赋为0

③:省略长度赋初值

int arr[] = {90, 80, 95, 85, 75};

arr[0]

arr[1]

arr[2]

arr[3]

arr[4]

90

80

95

85

75

注意:

数组的长度(数组的元素个数),由初值的个数确定。


浮游塔第23层:一维数组元素的引用

数组元素的引用就是使用数组数据元素。

与普通常量引用不同的是,由于数组储存了多个数据,所以在引用时除了给出数组名外,还要具体指出被引用的元素的下标。

具体的引用格式为: 数组名[下标];

注:在引用时,下标可以包含变量。

例如:

int k=0;  //初始化普通常量
a[k]=12;  //第一个元素赋值为12
a[5]=a[0]+10;//先计算第一个元素与数值10的和,在复制给第个各元素
scanf("%d",&a[2]);//将键盘输入的整数存入第三个元素中
a['B'-'A']=8;//第二个元素赋值为8
a[3]=a[1]+a[2*2] //将第二个元素和第五个元素的和存入第四个元素中

下面用一个例题来加强一下大家的印象。

题目:从键盘输入5个圆的半径,计算并输出它们的面积。(两个数据都保存在数组中)

3

2

1

解析如下:

#include<stdio.h>
#define Π 3.14//宏定义一个常量Π来表示圆周率,并赋以3.14
#define N 5   //宏定义一个常量N来表示圆的个数,并赋以5

int main( )
{
	int i;
	float r[N];  //N个圆的半径存放在数组r中
	float s[N];  //N个园的面积存放在数组s中
	for(i=0;i<N;i++)   //循环5次
	{
		printf("请输入第%d个圆的半径:",i+1);
		scanf("%f",&r[i]);  //从键盘接受半径的值,并按顺序保存到数组r种
		s[i]=Π*r[i]*r[i];  //由半径得到面积,并按顺序保存到数组s中
	}
	for(i=0;i<N;i++)
	{
		printf("第%d个圆的面积:%.2f\n",i+1,s[i]);
	}
}


浮游塔第24层:二维数组基础

二维数组定义的一般形式是:

类型说明符  数组名[常量表达式1][常量表达式2];

即:数据类型 数组名[行数][列数];

其中,常量表达式1表示第一维下标的长度,表达式2表示第二维下标的长度。例如:int a[3][4];

注意:若第一维的长度没有指定,则在定义的同时需要对其完成初始化。

二维数组的初始化也有多种方式,

①int arr[2][3]={{1,2,3},{4,5,6}};

②int arr[2][3]=

{

{1,2,3},

{4,5,6}

};

③或者把二者间的括号省略,即int arr[2][3]={1,2,3,4,5,6};

④又或者把行数省略,即int arr[][3]={1,2,3,4,5,6};但列数是绝对不能省略的!

 有关二维数组的元素大小以及行列数问题,可以参考以下代码。

#include <stdio.h>
int main()
{
	int arr[2][3]={{1,2,3},{4,5,6}};
	int i,j;

	for(i=0;i<2;i++)
	{
		for(j=0;j<3;j++)
		{
			printf("%d",arr[i][j]);
		}
		printf("\n");
	}

	printf("二维数组大小:%d\n",sizeof(arr));
	printf("二维数组一行大小:%d\n",sizeof(arr[0]));
	printf("二维数组元素大小:%d\n",sizeof(arr[0][0]));

	printf("二维数组行数:%d\n",sizeof(arr)/sizeof(arr[0]));
	printf("二维数组列数:%d\n",sizeof(arr[0])/sizeof(arr[0][0]));
	return 0;
}

二维数组的元素和一维数组的元素一样的,即元素的位置是相邻的,我们可以通过以下代码去验证它。

#include <stdio.h>
int main()
{
	int arr[2][3]={{1,2,3},{4,5,6}};
	
	printf("%p\n",arr[0][0]); 
	printf("%p\n",arr[0][1]);
	printf("%p\n",arr[0][2]);
	printf("%p\n",arr[1][0]);
	return 0;
}

 

 其中的%p是打印地址(指针地址)的,并且是以十六进制的形式打印。

但是会全部打完,即有多少位打印多少位,但这个长度受编译器影响。

32位编译器的指针变量为4个字节(32位),64位编译器的指针变量为8个字节(64位)。

二维数组各元素的地址关系:

int a[3][4];

若0<=i<3,0<=j<4,则二维数组的元素a[i][j]的地址可以有以下五种表达式:

&a[i][j]    a[i]+j    *(a+i)+j       &a[0][0]+4*i+j    a[0]+4*i+j

&a 表示二维数组地址。              a 表示首行地址。

&a[0] 表示首行地址。                 a[0] 表示首行首元素地址。

a[0][0] 表示首行首元素的值。     &a[0][0] 表示首行首元素地址。


浮游塔第25层:多维数组基础

(不断套娃)

多维数组的定义与二维数组类似,其语法格式具体如下:

数组类型修饰符  数组名[n1][n2]···[nn];

即:数据类型 数组名[层][行][列];

例如:int arr[3][4][5];

定义了一个三维数组,数组名是arr,数组的长度是3,每个数组的元素又是一个二维数组,

这个二维数组的长度是4,并且这个二维数组中的每个元素又是一个一维数组,

这个一维数组的长度是5,元素类型是int。

下面我会用最直观的初始化方式,来加强大家对于多维数组的印象。

#include<stdio.h>
int main()
{
	int i,j,k,arr[2][3][4]=
	{
		{
			{1,2,3,4},
			{2,3,4,5},
			{3,4,5,6}

		},
		{
			{4,5,6,7},
			{5,6,7,8},
			{6,7,8,9}
		}
	
	};

	for(i=0;i<2;i++)
	{
		for(j=0;j<3;j++)
		{
			for(k=0;k<4;k++)
			{
				printf("%d\t",arr[i][j][k]);
			}
			printf("\n");
		}
	}

	printf("三维数组大小:%d\n",sizeof(arr));
	printf("三维数组一层大小:%d\n",sizeof(arr[0]));
	printf("三维数组一行大小:%d\n",sizeof(arr[0][0]));
	printf("三维数组元素大小:%d\n",sizeof(arr[0][0][0]));

	printf("层:%d\n",sizeof(arr)/sizeof(arr[0]));
	printf("行:%d\n",sizeof(arr[0])/sizeof(arr[0][0]));
	printf("列:%d\n",sizeof(arr[0][0])/sizeof(arr[0][0][0]));

	return 0;
}


浮游塔第26层:一维数组作为函数参数

函数的语法格式:

数据类型 函数名(形参列表)  //多个参数之间用逗号分隔
{
    函数体;
}

如何在一个函数中使用另一个函数中定义的数组?

我们将数组作为参数传递到被调函数中的时候,需要传递什么过去?

因为数组元素的内存空间是连续的,所以我们大可不必将数组中所有的元素值都作为参数传递,只需要把数组的这块连续的内存空间首地址传递到被调函数即可。那么被调函数得到数组地址后,就可以对该数组内容进行访问。

其中,被调函数也存在多种情况。

  • 无参无返回值
  • 无参有返回值
  • 有参无返回值
  • 有参有返回值

一维数组作为函数参数:

形参:定义数据类型相同的数组或者定义指针

实参:数组名(数组首元素的地址)

若使用一维数组名作函数参数,则在被调用函数中,不需要考虑形式参数数组的大小

 需要注意的是,函数的参数传递有两种,一种是数值传递(单向),一种是地址传递(双向)。

地址传递会在学习了指针之后在进行讲解。

下面用一段代码来介绍数值传递。

#include <stdio.h>
#define  SIZE 5
int fun(int x[])
{
	int i=0;   //数组元素下标
	int sum=0; //和
	for(i=0;i<SIZE;i++)
	{
		sum+=x[i];//计算arr数组元素之和
	}
	return sum;//返回最终结果
}
int main( )
{
	int arr[SIZE]={1,2,3,4,5};
	int sum=fun(arr);//调用fun函数,
	printf("数组元素之和:%d\n",sum);
	return 0;
}

 我们可以发现:

fun函数的形参是int x[]或者int x[5]

main函数的调用函数为 fun(arr)

但不论形参数组的长度定义多少,计算后得到的形参数组的大小都是4

原因如下:

因为实际参数是数组名,数组名就是数组首元素的地址,即&arr[0],因此实际参数的本质就是地址。

那么形式参数用一个指针变量就可以接受保存实际参数,无需额外开辟多余的内存空间。

虽然形式参数定义的是数组,但是形式参数的本质仍然是指针

提示:不要在自定义函数中计算形式参数数组的长度,需要知道长度可以从主调函数中传递


浮游塔第27层:字符数组的定义

字符串的存储方式有字符数组字符指针,我们先来看看字符数组。

与定义其他类型的数组类似,字符数组定义的一般格式为:

char  数组名[元素个数1] [元素个数2] … [元素个数n] ;

存储字符时实际存储的是其对应的ASCII码值,虽然可以作为整数使用,但并不是真正的整形数据,其类型仍然为char型,即存储时占一个字节。

注:以下两个语句初始化的结果占用内存的情况是不同。

short c1[3]={65,66,67};

在内存中占3*sizeof(short)个字节

char c2[3]={}65,66,67]

再内存中占3*sizeof(char)个字节

因为字符串是由多个字符组成的序列,所以要想存储一个字符串,可以先把它拆成一个个字符,然后分别对这些字符进行存储,即通过字符数组存储。

例如:以下两个数组的定义是等价的。

char str1[30] = "Let's go";             // 字符串长度:8;数组长度:30
char str1[30] = { 'L', 'e', 't', '\'', 's',' ', 'g', 'o', '\0' };

存储字符串的数组一定比字符串长度多一个元素,以容纳下字符串终止符(空字符'\0')。

下列字符数组里存放的一定是字符串嘛?

char ch1[5]={‘a’,’b’,’c’,’d’,’e’};   没有使用’\0’结尾

char ch2[]=”Hello”;         是字符串

char ch3[5]={‘a’,’b’};         是字符串,未初始化的数组元素默认为0,也就是’\0’

char ch4[5]=”Hello”;        不是字符串,数组只存放了’H’,’e’,’l’,’l’,’o’,没有存放’\0’


浮游塔第28层:字符数组的初始化

字符数组只有在初始化的时候才能整体赋值,否则只能对字符数组逐个赋值。

字符数组的初始化与数组的初始化一样,要么定义时初始化,要么定义后初始化。

如果在定义字符数组时不进行初始化,则数组中各元素的值是不可预料的。

下面介绍初始化的两种方式:

用字符初始化/逐个字符赋值

如果用字符型数据初始化字符数组,那么其格式与其他类型的数组初始化格式无区别。

 char  ch[5]={‘a’,’a’,’a’,’a’,’a’};   //逐个全部初始化一维数组

则ch[0]~ch[4]的值均为’a’,也可以省略元素个数,

即”char ch[ ]={‘a’,’a’,’a’,’a’,’a’};元素个数自动确定为5。

也可以部分初始化,特点与前面所讲的普通一维数组相同。

但需要注意的是,没有得到数据的元素,会被自动赋以字符\0,即ASCII码值为0的字符。

再如:

char ch[3][4]={{‘a’,’a’,’a’,’a’},{‘b’,’b’,’b’,’b’},{‘c’,’c’,’c’,’c’}};  //逐个全部初始化二维数组

可以按行分段对全部或部分元素进行初始化,也可以按行连续对全部或部分元素进行初始化,并且也可以省略行下标,这些特点与其他类型的二维数组相同。

用字符串初始化

char str[7]={“string”};

char str[ ]={“string”};

注:用字符串对字符数组初始化时,如果不省略元素个数,那么元素个数应至少比字符串包含的可显示字符个数多一个。

       因为系统会自动在字符串的最后加上字符’\0’,它也要占一个存储位置,算作一个数组元素。


 浮游塔第29层:字符数组的输入输出

逐个字符的形式:
采用"%c"格式符与循环结构配合,

以逐个字符的方式实现“字符串”的输入和输出

 整串输入和输出

#include<stdio.h>
int main( )
{
	char ch[6];
	printf("输入一个字符串:");
	scanf("%s",&ch);
	printf("字符串:%s\n",ch);
	return 0;
}

注意:在整串输入时,一定要空出一个位置给'\0',否则会出现以下情况。

run-time check failure #2-stack around the variable'ch'was corrupted

(运行时检查失败#2 -围绕变量“ch”的堆栈已损坏)


 浮游塔第30层:字符数组的引用

字符数组的引用方式与其他类型数组引用方式相同。

#include <stdio.h>
#define N 5 //宏定义常量N,表示数组长度
int main( )
{
	int i; //循环控制变量
	char str[N];
	printf("请输入%d个字符:",N); //输入的字符个数,不能超过N个
	for(i=0;i<N;i++)
	{
		scanf("%c",&str[i]);
	}
	printf("第1、3、5个字符:");
	printf("%c",str[0]);
	printf("%c",str[2]);
	printf("%c",str[4]);
	printf("\n");
	return 0;
}


浮游塔隐藏层:数组的应用

数组在日后制作首个C语言项目[学生成绩管理系统]的时候会发挥很大的作用。

在其中的功能有,

  • 数据的添加和删除
  • 数据查询
  • 数据修改
  • 数据的排序

感兴趣的可以看看这篇由数组和结构体制作的学生成绩管理系统:

【C/C++/初学者】基于结构体数组的学生信息管理系统

后记

okay,这就是浮游塔第21至30层的内容,依旧希望各位能够坚持下去。

突然发现写博客能让人上瘾,今天光是写博客查资料就花了五六个小时。

下期的内容是函数的天下,预计在1~2天后发布,敬请期待,欸嘿。

第④期——函数链接:

[编程神域 C语言浮游塔 第④期] 函数的基本知识_渡过晚枫的博客-CSDN博客

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渡过晚枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值