谭浩强《C程序设计》(第五版)第六章

引例:

一个班有30个学生,每个学生有一个成绩,要求这30名学生的平均成绩。

如何表示30个学生成绩?

可以用30个float型白能量进行记录,但是繁琐,没有反映出这些数据间的内在联系

解决方法:

因为是同一类型性质的数据,就可以用同一个名字代表,名字的下标表示这是第几个学生的成绩。一批具有同名同属性的数据就组成一个数组,他们的名字就是数组名

数组是一组有序数据的集合,数组中各数据的排列是有一定规律的,下标代表数据在数组中的序号。

用数组名和下标即可唯一地确定数组中的元素。

数组中的每一个元素都属于同一个数据类型

怎样定义和引用一维数组

一维数组是数组中最简单的,它的元素只需要用数组名加一个下标,就能唯一确定。

定义一维数组

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

如果需要使用数组,必须在程序中先定义数组,定义一维数组的一般形式如上所示,例如int a[5];它表示定义了一个整型数组,数组名为a,此数组包含5个整型元素,数组长度为5,这5个元素在数组中存储方式如下图所示,下标从0开始。 

 数组名的命名规则和变量名相同,遵循标识符命名规则。

在定义数组的时候,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。如果并未事先指定n的值,就将数组定义为int a[n];则会出现如下报错。如果想要在常量表达式中输入符号常量n,可以加上define预处理,指定n的大小。

 常量表达式中可以包括常量和符号常量,不能包含变量。

引用一维数组

数组名[下标]

 在定义数组并对其中各元素赋值之后,就可以引用数组中的元素了。只能引用数组元素,而不能一次整体调用整个数组全部元素的值。

数组元素与一个简单变量的地位和作用相似。

“下标”可以是整形常量或整型表达式。

注意:

定义数组时用到的“数组名[常量表达式]”和引用数组元素时用的“数组名[下标]”形式相同,但含义不相同。

int a[10];
//前面有int,这是定义数组,指定数组包含10个元素
t=a[6];
//这里的a[6]表示引用a数组中序号为6的元素

对10个数组元素依次赋值为0,1,2,3,4,5,6,7,8,9,要求按逆序输出

解题思路:

因为有10个元素,所以需要定义一个长度为10的数组。由题知数组中的元素都为整型,所以数组可以定义为整型数组。完成定义之后给数组赋值。

编写程序:

#include <stdio.h>

int main() {
	int a[10], i;
	for (i = 0; i < 10; i++)	//对数组元素赋值
		a[i] = i;
	for (i = 9; i >= 0; i--)	//逆序输出数组元素
		printf("%d ", a[i]);
	printf("\n");
	return 0;
}

 运行结果:

 一维数组的初始化

为了使程序简洁,常在定义数组的同时给各数组元素赋值,这成为数组的初始化

(1)在定义数组时对全部数组元素赋予初值,例如:

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

将数组中各元素的初值顺序放在一对花括号中,数据间用逗号隔开。花括号内的数据就称为初始化列表。使用单步运行可以发现经过初始化,数组中元素的状态如下图所示:

(2)可以只给数组中的一部分元素赋值,例如:

int a[5]={0,1,2};

 单步运行结果如下图所示:

 通过单步运行的结果我们可以发现,如果我们只对数组中一部分元素赋值,那么元素赋值是从下标0开始的,一直到赋值结束,没有被赋值到的元素则默认为值为0。

(3)给数组中全部元素赋值为0,可以有以下两种形式:

int a[5]={0,0,0,0,0};
int a[5]={0};    //未赋值的部分元素自动设定为0

(4)在对全部数组元素赋值时,由于数据的个数已经确定,因此可以不指定数组长度,例如:

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

但是上面的写法会让系统默认数组的元素个数为5,如果数组长度与提供初值的个数不相同,则方括号中的数组长度不能省略。

定义和引用二维数组

有3个小分队,每队有6名队员,要把这些队员的工资用数组保存起来以备检查。如下图:

队员1队员2队员3队员4队员5队员6
1分队245618471243160023462757
2分队304520181725202024581436
3分队142711751046197614772018

二维数组常称为矩阵。把二维数组写成行和列的排列形式,如上图,可以有助于形象化地理解二维数组的逻辑结构。 

定义二维数组

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

二维数组的一般形式如上所示,例如:

float a[3][4],b[5][10];

 定义a为3*4(3行4列)的数组,b为5*10的数组。

 数组在计算机中如上所示,由上图可以发现,我们可以将二维数组分解成一维数组,如果二维数组a有i行j列,那么我们可以将a分解成i个一维数组,每一个一维数组里面都有j个元素。这样我们就可以将a[i]看做是一维数组的数组名。

注意:

用矩阵形式表示二维数组只是为了表示形象,实际上在内存中,各元素是连续存放的,是线性的。在二维数组中元素排列的顺序是按行存放的。

引用二维数组

数组名[下标][下标]

“下标”可以是整形常量或整型表达式。 数组元素可以出现在表达式中,也可以被赋值,例如:

b[1][2]=a[2][3]/2;

注意:

在引用数组元素时,下标值应在已定义的数组大小的范围内。同一维数组一样,二维数组的下标同样是同0开始的,所以如果是i*j的二维数组,那么它下标最小为[0][0],最大为[i-1][j-1]。

二维数组的初始化

(1)分行给二维数组赋初值,例如:

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

赋值结果:

 这种赋值方法比较直观,一个花括号对应一行。

(2)可以将所有数据写在一个花括号里面,按数组元素在内存中的排列顺序对各元素赋值,例如:

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

赋值结果与之前相同,但是这种方式不直观,容易遗漏,也不易检查。

(3)可以对部分元素赋值,例如:

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

赋值结果:

 通过赋值结果可以发现,同一维数组一样,除了被赋值元素以外,其余元素皆默认值为0。因为一个花括号对应一行,所以上面数组的赋值是对每一行从头开始赋值。

(4)如果对全部元素进行赋值,则定义数组时,对行数不必指定,但是对列数一定要指定。例如:

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

赋值结果:

 在定义的时候也可以省略部分元素的赋值,但是赋值的时候一定要分行赋值,即有几行就在里面分几个花括号,例如:

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

赋值结果:

但是不可以省略列数。

字符数组 

字符型数据是以字符的ASCII代码存储在存储单元中的,一般占一个字节。由于ASCII代码也属于整数形式,因此字符类型也可以归类于整型类型中。

定义字符数组

char c[10];
c[0]='I'; c[1]=' ';c[2]='a';c[3]='m';c[4]=' ';
c[5]='h';c[6]='a';c[7]='p';c[8]='p';c[9]='y';

赋值结果:

 由于字符型数据是以整数形式(ASCII代码)存放的,因此也可以用整型数组来存放字符数据,例如:

int c[10];
c[0]='a'; 	//合法,但浪费存储空间

字符数组的初始化

对字符数组初始化,最容易理解的方式是用“初始化列表”,把各个字符依次赋给数组中各元素。

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

如果花括号中提供的初值个数(即字符个数)大于数组长度,则出现语法错误。

如果初值个数小于数组长度,则只将这些字符赋给数组中从头开始的顺序的元素,其余的元素自动定位空字符('\0')。例如:

char c[10] = { 'c',' ','p','r','o','g','r','a','m'};

赋值结果:

 如果提供的初值个数与预定的数组长度相同,在定义的时候可以省略数组长度,系统会自动根据初值个数确定数组长度。例如:

char c[] = { 'c',' ','p','r','o','g','r','a','m'};
//数组c的长度自动定为10

引用字符数组中的元素

输出一个已知的字符串。

解题思路:

先定义一个字符数组,并用“初始化列表”对其赋值,然后逐个循环输出此字符数组中的字符。

编写程序:

#include <stdio.h>
int main()
{
	char c[15]={'I',' ','a','m',' ','a',' ','s','t','u','d','e','n','t','.'};
	int i;
	for(i=0;i<15;i++)
		printf("%c",c[i]);
	printf("\n");
	return 0;
}

 运行结果:

输出一个菱形图

 解题思路:

每行包括5个字符,其中有的是空白字符,有的是'*'字符,记下在每行中'*'出现的位置。定义一个字符型的二维数组,用“初始化列表”进行初始化。这样字符数组中已存放一个菱形图案,然后用嵌套的for循环输出字符数组中所有元素。

编写程序:

#include <stdio.h>
int main()
{	char diamond[][5]={{' ',' ','*'},{' ','*',' ','*'},{'*',' ',' ',' ','*'},
	{' ','*',' ','*'},{' ',' ','*'}};
	int i,j;
	for (i=0;i<5;i++)
	{		for (j=0;j<5;j++)
		printf("%c",diamond[i][j]);
		printf("\n");
	}
	return 0;
}

运行结果:

 字符串和字符串结束标志

在C中,是将字符串作为字符数组来处理的。在实际工作中,人们关心的往往是字符串的有效长度而不是字符数组的长度。为了测定字符串的实际长度,C规定了一个“字符串结束标志”,以字符'\0'作为结束标志。

注意:

C系统在用字符数组存储字符串常量的时候会自动加一个'\0'作为结束符

在定义字符数组时应该估计实际字符串长度,保证数组长度始终大于字符串实际长度。

如果在一个字符数组中先后存放多个不同长度的字符串,则应使数组长度大于最大的字符串的长度。

printf("How do you do?\n");
/*在向内存中存储时,系统自动在最后一个字符′\n′的后面加了一个′\0′,作为字符串结束标志。
在执行printf函数时,每输出一个字符检查一次,看下一个字符是否为′\0′,遇′\0′就停止输出。*/
char c[]={"I  am  happy"}; 
/*或*/ 
char c[]="I am happy";

用一个字符串(注意字符串的两端是用双引号而不是单引号括起来的)作为字符数组的初值。

注意:

数组c的长度不是10,而是11。因为字符串常量的最后由系统加上一个′\0′。

char c[]={′I′, ′ ′, ′a′,′m′, ′ ′,′h′,′a′,′p′,′p′,′y′,′\0′};
//不等于
char c[]={′I′, ′ ′, ′a′,′m′, ′ ′,′h′,′a′,′p′,′p′,′y′};
char c[10]={"China"};
//数组c的前5个元素为: ′C′,′h′,′i′,′n′,′a′,第6个元素为′\0′,后4个元素也自动设定为空字符。

字符数组的输入输出

(1) 逐个字符输入输出。用格式符“%c”输入或输出一个字符。

(2) 将整个字符串一次输入或输出。用“%s”格式符,意思是对字符串的输入输出。

说明:

(1)输出的字符中不包括结束符'\0'

(2)用“%s”格式符输出字符串时,printf函数中的输出项是字符数组名,而不是数组元素名。

(3)如果数组长度大于字符串的实际长度,也只输出到遇'\0'结束。

(4)如果一个字符数组中包含一个以上'\0',则遇第一个'\0'时输出就结束。

(5)可以用scanf函数输入一个字符串。如果利用一个scanf函数输入多个字符串,则应在输入时以空格分隔。

注意:

scanf函数中的输入项如果是字符数组名,不要再加地址符&,因为在C中数组名代表的是该数组第一个元素的地址。

使用字符串处理函数

输出字符串的函数

puts(字符数组)

作用:

将一个字符串(以'\0'结束的字符序列)输出到终端

用puts函数输出的字符串中可以包含转义字符

在用puts输出时将字符串结束标志'\0'转换成'\n',即输出完字符串后换行。

#include <stdio.h>
int main()
{
	char str[]={"China\nBeijing"};
	puts(str);
	return 0;
}

 输入字符串的函数

gets(字符数组)

作用:

从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址。

如果从键盘输入: Computer

将输入的字符串″Computer″送给字符数组str(请注意,送给数组的共有9个字符,而不是8个字符),返回的函数值是字符数组str的第一个元素的地址。 

注意:

用puts和gets函数只能输出或输入一个字符串。

字符串连接函数

strcat(字符数组1,字符数组2)

作用:

把两个字符数组中的字符串连接起来,把字符串2接到字符串1的后面,结果放在字符数组1中,函数调用后得到一个函数值——字符数组1的地址。

字符数组1必须足够大,以便容纳连接后的新字符串。

连接前两个字符串的后面都有′\0′,连接时将字符串1后面的′\0′取消,只在新串最后保留′\0′。

#include <stdio.h>
#include <string.h>

int main() {
	char str1[30] = { "People′s Republic of " };
	char str2[] = { "China" };
	printf("%s", strcat(str1, str2));
	return 0;
}

字符串复制函数

strcpy(字符数组1,字符数组2) 

作用:

将字符串2复制到字符数组1中去。

字符数组1必须定义得足够大,以便容纳被复制的字符串2。字符数组1的长度不应小于字符串2的长度。

 “字符数组1”必须写成数组名形式,“字符串2”可以是字符数组名,也可以是一个字符串常量。

若在复制前未对字符数组1初始化或赋值,则其各字节中的内容无法预知,复制时将字符串2和其后的′\0′一起复制到字符数组1中,取代字符数组1中前面的字符,未被取代的字符保持原有内容。

不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组。字符数组名是一个地址常量,它不能改变值,正如数值型数组名不能被赋值一样。  

可以用strncpy函数将字符串2中前面n个字符复制到字符数组1中去。 将str2中最前面n个字符复制到str1中,取代str1中原有的最前面n个字符。但复制的字符个数n不应多于str1中原有的字符(不包括′\0′)。 

字符串比较函数

strcmp(字符串1,字符串2)

作用:

比较字符串1和字符串2。

字符串比较的规则是: 将两个字符串自左至右逐个字符相比(按ASCII码值大小比较),直到出现不同的字符或遇到′\0′为止。

        (1) 如全部字符相同,则认为两个字符串相等;

        (2) 若出现不相同的字符,则以第1对不相同的字符的比较结果为准。

比较的结果由函数值带回。

        (1) 如果字符串1与字符串2相同,则函数值为0。

        (2) 如果字符串1>字符串2,则函数值为一个正整数。

        (3) 如果字符串1<字符串2,则函数值为一个负整数。 

注意:

对两个字符串比较不能直接用str1>str2进行比较,因为str1和str2代表地址而不代表数组中全部元素,而只能用 (strcmp(str1,str2)>0)实现,系统分别找到两个字符数组的第一个元素,然后顺序比较数组中各个元素的值。

#include <stdio.h>
#include <string.h>

int main() {
	char str1[80] = "string";
	char str2[80] = "compare";
	if (strcmp(str1, str2) > 0)
		printf("yes\n");
	else printf("no\n");
	if (strcmp("China","Korea") > 0)
		printf("yes\n");
	else printf("no\n");
	if (strcmp(str1,"Beijing") > 0)
		printf("yes\n");
	else printf("no\n");
	return 0;
}

测字符串长度的函数

strlen(字符数组) 

作用:

测试字符串长度的函数。函数的值为字符串中的实际长度(不包括′\0′在内)。 

#include <stdio.h>
#include <string.h>
int main()
{
	char str[10]="China";
	printf("%d,%d\n",strlen(str),strlen("China"));	
}

转换为大小写的函数

strlwr(字符串) 

作用:

将字符串中大写字母换成小写字母。 

strupr(字符串)

作用:

将字符串中小写字母换成大写字母。 

注意:

以上介绍了常用的8种字符串处理函数,它们属于库函数。

库函数并非C语言本身的组成部分,而是C语言编译系统为方便用户使用而提供的公共函数。不同的编译系统提供的函数数量和函数名、函数功能都不尽相同,使用时要小心,必要时查一下库函数手册。

在使用字符串处理函数时,应当在程序文件的开头用#include <string.h>把string.h文件包含到本文件中。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

箬渊凡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值