如果需要处理1名学生的10门课程的成绩,用什么来存储这些数据?第一种方法:可以定义10个变量,每个变量中存放1门成绩。但这种方法定义的变量过多,若课程数目更多,处理起来势必更加繁琐。第二种方法:设想用一维数组存储以下表格中的成绩。
目录
3.2.3使用scanf函数和printf函数为二维数组输入输出字符串
3.3.6求字符串长度函数(实际字符串长度,不包含‘\0'在内)
1、一维数组
1.1一维数组的定义
一维数组定义格式为:
类型说明符 数组名 [整型常量或整型常量表达式]
说明:
(1)类型说明符可以是int,char等,用于说明数组中每个元素的类型;
(2)数组名即:给数组起的名字,用合法的用户标识符命名,注意不能与其他变量同名;
(3)整型常量或整型常量表达式表示数组包含的元素个数,要求一定是正整数,
并且不能是变 量。(C语言中除了动态分配内存外,变量的内存分配一般都是
发生在程序编译阶段。变量获取值一般是在程序运行时,那么编译时变量中还没
有存入有效的值,变量中有可能是随机值,因此不能使用变量为数组分配内存。)
(4)数组元素个数也可以用字符型常量表达式来表示,但很少使用。
1.2一维数组元素的引用
可以通过数组名和下标来引用数组的元素。一维数组的引用格式:数组名[下标],下标可以是变量
说明:
(1)数组必须定义,再使用。
(2)只能逐个引用数组元素,不能一次引用整个数组。
例如:int a[10];
1、引用a数组各元素的正确格式为:a[0]、a[1]……a[9](数组的下标从第0号开始)。
2、若有a=1;不合法。数组名a在程序中有特定的含义,它代表数组的起始地址,它的意义等价于&a[0]。
3、若有a[10]=1;也不合法。a[10]是下标为10的元素,a数组的末尾元素是a[9]。若使用a[10],C编译系统会提示数组越界错误。
(3)下标可以是整型常量、整型常量表达式、整型变量或整型变量表达式(也可以是字符型的常量、变量、表达式,但很少用),它表示元素的序号。
(4)一维数组在内存中依次连续存放,先存放下标为0的元素,再放下标为1的元素,依次直至存放完所有元素。
1.3一维数组的初始化
定义一维数组的同时给数组元素赋初值称为一维数组的初始化。其一般格式为:
类型说明符 数组名[N] ={初值1,初值2,初值3,.......,初值N};
其中,N是表示数组元素个数的敞开。
一维数组的初始化方式有以下几种:
(1)全部元素初始化,例如:char a[3]={'1','2','3','\n'}; int b[5]={2,11,3,14,5};
(2)部分元素初始化:int a[10]={0,1,2}; char a[10]={'1','2'};
(3)全部元素初始化为0:int a[10]={0};
1.4冒泡排序
冒泡算法逻辑过程:
从小到大:数值小的向上浮(向左换),若小于后一个数就不换,然后接着往下,
从第0趟开始,随着趟数的递增,每一趟相邻两两位置比较次数递减
举例说明:
for(i=0;i<=3;i++){//外循环,趟数
//如果R[i]的值>R[i+1]的值,则交换,i自增1
for(j=0;j<=3-i;j++){//内循环,比较次数
//如果R[j]的值<=R[j-1]的值,则不交换,j自增1
}
}
1、趟数和次数的逻辑关系:
假设趟数用i表示,次数用j表示。一趟中可能包含多次的比较和交换,次数随着趟数的增加而减少。由以上过程中可以看出趟数i的变化范围是0~3。
①当i为0时,次数j的变化范围是0~3;
②当i为1时,次数j的变化范围是0~2;
③当i为2时,次数j的变化范围是0~1;
④当i为3时,次数j的变化范围是0。
总结规律,用二重循环来表示趟数和次数的变化如下:
for(i=0;i<=3;i++)
for(j=0;j<=3-i;j++)
2、核心比较、交换过程为:
参与比较、交换的两个相邻元素由j确定其下标,分别为R[j]和R[j+1]。
如果(R[j]的值>R[j+1]的值)
交换R[j]和R[j+1]
否则
不交换
交换值,需要定义一个中间量temp,用程序表示
int temp;
if(R[j}>R[j+1]
{
temp=R[j];
R[j]=R[j+1];
R[j+1]=R[j];
}
3、写出完整的程序:
1.4.1 程序练习
题目1:将程序推广为对包含N个元素的数组排序。
#include<stdio.h>
#define N 10
int main(){
int R[N],i,j,temp;
printf("输入数组的元素值:");
for(i=0;i<=N-1;i++){
scanf("%d",&R[i]);
}
printf("排序前:");
for(i=0;i<=N-1;i++){
printf("%d,",R[i]);
}
printf("\n");
for(i=0;i<=N-2;i++){
for(j=0;j<=N-2-i;j++){
if(R[j]>R[j+1]){
temp=R[j];
R[j]=R[j+1];
R[j+1]=temp;
}
}
}
printf("排序后:");
for(i=0;i<=N-1;i++){
printf("%d,",R[i]);
}
printf("\n");
return 0;
}
题目2:改进冒泡算法 :设置一个标识量flag,若某趟中一次交换都没有进行,即:空趟,说明此趟过后数据已完全排列好,不需要进行后面的过程,程序结束。
#include<stdio.h>
#define N 10
int main(){
int R[N],i,j,temp;
int flag;
printf("输入数组的元素值:");
for(i=0;i<=N-1;i++){
scanf("%d",&R[i]);
}
printf("排序前:");
for(i=0;i<=N-1;i++){
printf("%d,",R[i]);
}
printf("\n");
for(i=0;i<=N-2;i++){
flag=1;//每趟开始时,将其设置为1
for(j=0;j<=N-2-i;j++){
if(R[j]>R[j+1]){
temp=R[j];
R[j]=R[j+1];
R[j+1]=temp;
flag=0;//若发生置换,则将标识量置为0
}
}
if(flag==1){
break;//在本趟的末尾进行空趟判断 若flag仍为1,判断为空趟,直接退出外循环
}
}
printf("排序后:");
for(i=0;i<=N-1;i++){
printf("%d,",R[i]);
}
printf("\n");
return 0;
}
题目3:从键盘输入10个学生的成绩,计算出平均成绩,并输出高于平均成绩分的学生成绩。
//从键盘输入10个学生的成绩,计算出平均成绩,并输出高于平均成绩分的学生成绩。
#include<stdio.h>
#define N 10
int main(){
int R[N];
int i,sum=0;
float average;
for(i=0;i<=N-1;i++){
printf("请输入第%d个学生的成绩:",i+1);
scanf("%d",&R[i]);
}
for(i=0;i<=N-1;i++){
printf("第%d个学生的成绩为%d分\n",i+1,R[i]);
}
for(i=0;i<=N-1;i++){
sum+=R[i];
}
average=(float)sum/N;
printf("学生的平均成绩为:%.2f\n",average);
for(i=0;i<=N-1;i++){
if(R[i]>average){
printf("第%d个学生成绩为%d高于平均成绩\n",i+1,R[i]);
}
}
return 0;
}
1.5查找方法
有N个数按由小到大的顺序存放在一个数组中,输入一个数,要求分别使用顺序查找法和折半查找法找出该数是数组中的第几个元素值(若数组中有多个元素与该数相等,只输出第一个数是数组中的第几个元素值即可。)如果该数不在数组中,则打印输出“无此数”的信息
1.5.1顺序查找法
#include<stdio.h>
#define N 8
int main()
{
int a[N];
int n,i;
printf("给数组a按从小到大的输入%d个值:",N);
for(i=0;i<=N-1;i++){
scanf("%d",&a[i]);
}
printf("请输入需要查找的数:");
scanf("%d",&n);
if(n<a[0]||n>a[N-1]){
printf("无此数!!!");
}
else{
for(i=0;i<=N-1;i++){
if(n==a[i]){
printf("是第%d个数",i+1);
break;
}
if(n<a[i]){
printf("无此数!!\n");
break;
}
}
}
return 0;
}
1.5.2折半查找法
//折中查找法
#include<stdio.h>
#define N 8
int main(){
int a[N];
int n,i,low=0,high=N-1,mid;
printf("给数组a按从小到大的输入%d个值:",N);
for(i=0;i<=N-1;i++){
scanf("%d",&a[i]);
}
printf("请输入需要查找的数:");
scanf("%d",&n);
if(n>=a[0]&&n<=a[N-1]){
while(low<=high){
mid=(low+high)/2;
if(n<a[mid]){
high=mid-1;
}
else if(n>a[mid]){
low=mid+1;
}
else if(n==a[mid]){
printf("是第%d个数",mid+1);
break;
}
}
if(low>high){
printf("无此数!!\n");
}
}
else {
printf("无此数!\n");
}
return 0;
}
2、二维数组
如果需要处理3名学生的期末成绩,每名学生有4门课程的成绩,用什么来存储这些数据?可以设想用二维数组来存储。
2.1二维数组的定义
二维数组的定义格式为:
类型说明符 数组名[整型常量M或整型常量表达式M][整型常量N或整型常量表达式N];
说明:
(1)常量或常量表达式M和N分别表示二维数组的行数和列数,只能为正整数。
(2)二维数组可以看成是由几个一维数组组成的。
(3)二维数组在内存中连续存放,先顺序存放第一行的元素,再存放第二行的元素,依次直至存放完所有元素。
2.2二维数组元素的引用
二维数组的引用格式:数组名[行下标][列下标]——先行后列
例如:a[0][1]指的是a数组中的第0行第1列的元素
注意下标不要越界。
2.3二维数组的初始化
定义二维数组的同时给数组元素赋初值称为二维数组的初始化。一般格式为:
类型说明符 数组名[M][N]={初值1,初值2,……,初值N-1,初值N,……,初值M*N-1};
或者:
类型说明符 数组名[M][N]={{初值1,初值2,初值3……,初值N-1},……,{...初值M*N-1}};
其中,M和N分别为二维数组的行数和列数。
二维数组的初始化方式有以下几种:
(1)分行赋初值:
例如:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
赋初值时,数组的行下标可以省略。例如:int a[ ][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};说合法的
(2)全部数组写在一个花括号内,按数组排列的顺序对各元素赋初值。
例如:int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};这种方式没有第一种直观
(3)对部分元素赋初值:
1、int a[3][4]={0,1,2};功能:仅对a[0][0]、a[0][1]、a[0][2]赋值,未赋值的元素初始化为0.
2、int a[3][4]={{1},{5,6},{9}};功能仅对a[0][0]、a[1][0]、a[1][1]、a[2][0]赋值,未赋值的元素初始化为0.
题目1:求一个3*4矩阵的最大值及其所在行列下标。
//求一个3*4矩阵的最大值及其所在行列下标。
#include<stdio.h>
int main(){
int a[3][4],i,j,max,row=0,col=0;
for(i=0;i<3;i++){
for(j=0;j<4;j++){
scanf("%d",&a[i][j]);
}
}
max=a[0][0];
for(i=0;i<3;i++){
for(j=0;j<4;j++){
if(max<a[i][j]){
max=a[i][j];
row=i;
col=j;
}
}
}
printf("max=%d,row=%d,col=%d\n",max,row,col);
return 0;
}
题目2: 3名学生各有4门课程的成绩,计算每个学生的平均成绩。
//3名学生各有4门课程的成绩,计算每个学生的平均成绩。
#include<stdio.h>
int main(){
int score[3][4]={{90,88,95,77},{66,80,65,96},{84,75,68,92}};
int i,j;
float aver[3]={0};
for(i=0;i<3;i++){
for(j=0;j<4;j++){
aver[i]+=score[i][j];
}
aver[i]=aver[i]/4;
}
for(i=0;i<3;i++){
printf("第%d个学生的平均成绩为%.1f\n",i+1,aver[i]);
}
return 0;
}
题目3:打印输出杨辉三角形
//打印杨辉三角形
/*
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
……
*/
#include<stdio.h>
int main(){
int a[10][10],i,j;
for(i=0;i<=9;i++)
for(j=0;j<=9;j++){
if(i>=j){
if(j==0){
a[i][j]=1;
}
else if(i==j){
a[i][j]=1;
}
else{
a[i][j]=a[i-1][j-1]+a[i-1][j];
}
printf("%-5d",a[i][j]);
if(i==j){
printf("\n");
}
}
}
return 0;
}
3、字符串数组
在程序中如果要处理姓名、地址等类型的数据,需要使用什么样的类型呢?显然用int,char,float等类型处理是不恰当的。可以将姓名、地址等看成一系列的字符,用字符串常量来描述,简称字符串。
3.1字符串
字符串常量,简称字符串,是用双引号括起来的字符序列。c语言规定,字符串常量的结尾以'\0'是C语言中规定的“字符串结束标志”,也称为“结束符”。书写字符串时,不需要用户写它,由C编译系统自动加上,并且不在屏幕上显示。
例如:“C++\n” 字符串长度4字节,占用内存空间:5字节
“C++程序设计”字符串长度11字节,占用内存空间:12字节
字符数组中可以存储普通字符序列,也可以存储字符串,两者依据字符数组末尾是否有字符串结束符'\0'来区分。若字符数组末尾有'\0‘,则存储的是字符串,否则存储的是普通字符序列。
若要重新给字符数组(字符串变量)赋值,使它改而存放别的字符串,应注意以下几点:
(1)应充分估计新字符串所需的最大空间,不要出现越界情况。
(2)不能使用赋值语句对字符串集体赋值,而应该使用赋值语句为每个字符数组元素单独赋值。
3.2字符数组的输入输出
3.2.1、使用scanf函数输入字符串到字符数组中。
有两种方式:
(1)以单个字符的格式逐个输入
例如:char c[5];
scanf("%c%c%c%c%c",&s[0],&s[1],&s[2],&s[3],&s[4]);
(2)字符串的格式输入
例如:char c[5];
scanf("%s",c);
3.2.2使用printf函数将字符数组中的字符串输出。
有两种方式:
(1)以单个字符的格式逐个输出
例如char c[5];
printf("%c%c%c%c%c",s[0],s[1],s[2],s[3],s[4]);
(2)以字符串的格式输出
例如:char c[5];
printf("%s",c);
程序练习:
//删除字符串中的空格,并输出
#include<stdio.h>
int main(){
int i,j;
char ch[]="I am happy";
for(i=0;ch[i]!='\0';i++){
if(ch[i]==' '){
for(j=i+1;ch[j-1]!='\0';j++){
ch[j-1]=ch[j];
}
}
}
printf("%s\n",ch);
return 0;
}
3.2.3使用scanf函数和printf函数为二维数组输入输出字符串
二维数组可以视为由一维数组组成的。如果将一维字符数组看作是存放字符串的变量,那么二维字符数组就可以看作是存放字符串的一维字符串数组。例如:定义char c[3][5];相当于定义了3个字符串变量。c[0]、c[1]、c[2]分别是3个字符串的起始地址,可以使用scanf和printf函数为其输入输出字符串。
//利用二维字符数组输入、输出字符串
#include<stdio.h>
int main(){
char c[3][5];
printf("请输入3个字符串:\n");
scanf("%s%s%s",c[0],c[1],c[2]);
printf("打印输出3个字符串:\n");
printf("%s\n%s\n%s\n",c[0],c[1],c[2]);
return 0;
}
3.3字符串处理函数
C语言提供了多个常用的字符串处理函数,有字符串输入、输出、比较、连接及求字符串的长度等函数。这些函数均在C编译系统提供的头文件string.h中定义,因此要使用这些函数,需将此文件包含进来(有些C编译系统会自动包含此头文件,不需要用户包含)。
3.3.1输入函数
gets 格式: gets(字符数组);
gets(s1);gets(s2);=scanf("%s%s",s1,s2);
3.3.2输出函数
puts 格式: puts(字符数组);
puts(s1);puts(s2);=scanf("%s%s",s1,s2);
3.3.3连接函数
strcat 格式:strcat(字符数组1,字符数组2);
将字符数组2连在字符数组1后面
3.3.4复制函数
strcpy 格式:strcpy(字符数组1,字符数组2);
strcpy(str1,str2,2);
将str2中字符串前2个字符复制到str1字符串的前2个字符,相当于str1中字符串前两个字符被str2前两个字符替代。
3.3.5比较函数
strcmp 格式:strcmp(字符数组1,字符数组2);
字符串比较只能用strcmp(str1,str2)不能使用>,<,=直接比较
字符串1 < 字符串2,函数的结果为负整数,一般为-1
字符串1==字符串2,函数的结果为0
字符串1>字符串2,函数的结果是正整数,一般为1
3.3.6求字符串长度函数(实际字符串长度,不包含‘\0'在内)
strlen 格式:strlen(字符数组或字符串);
3.3.7字符串大小写转换函数
strupr(字符数组) 小写转大写
strlwr(字符数组) 大写转小写
strupr函数实现的功能是将字符数组中所存字符串的小写字母转换成大写字母
strlwr函数实现的功能是将字符数组中所存字符串的大写字母转换成小写字母
3.3.8程序练习
题目1: 使用strcat函数实现两个字符串的连接
//使用strcat函数实现两个字符串的连接
#include<stdio.h>
#include<string.h>
int main(){
char s1[20]="Hello";
char s2[20]="World";
puts("两个字符串的连接的结果为:");
puts(strcat(s1,s2));
puts("连接后s1的输出结果为:");
puts(s1);
puts("连接后s2的输出结果为:");
puts(s2);
return 0;
}
题目2:不使用strcat函数实现字符串连接功能
//不使用strcat函数实现两个字符串的连接
#include<stdio.h>
int main()
{
char s1[20]="Hello";
char s2[20]="World!";
int i=0,j=0;
while(s1[i]!='\0'){
i++;
}
while(s2[j]!='\0'){
s1[i]=s2[j];
i++;
j++;
}
s1[i]='\0';//在新串结尾处加上'\0'
puts("字符串连接后s1的结果:");
puts(s1);
puts("字符串连接后s2的结果:");
puts(s2);
return 0;
}
题目3:使用strcpy实现字符串的拷贝
#include<stdio.h>
#include<string.h>
int main(){
char s1[20]="Hello";
char s2[20]="World!";
puts("两个字符串的连接的输出的结果:");
puts(strcpy(s1,s2));
puts("字符串连接后s1的结果:");
puts(s1);
puts("字符串连接后s2的结果:");
puts(s2);
return 0;
}
题目4:不使用strcpy函数实现字符串的拷贝
//不使用strcpy函数实现字符串的拷贝
#include<stdio.h>
int main()
{
char s1[20]="Hello";
char s2[20]="World!";
int i=0;
while(s2[i]!='\0'){
s1[i]=s2[i];
i++;
}
s1[i]='\0';
puts("字符串连接后s1的结果:");
puts(s1);
puts("字符串连接后s2的结果:");
puts(s2);
return 0;
}
题目5:使用strcmp函数实现两个字符串比较的功能
//使用strcmp函数实现两个字符串比较的功能
#include<stdio.h>
#include<string.h>
int main(){
char s1[20]="Hello";
char s2[20]="World!";
int cmp;
cmp=strcmp(s1,s2);
if(cmp>0){
puts("s1>s2");
}
if(cmp==0){
puts("s1==s2");
}
if(cmp<0){
puts("s1<s2");
}
puts("两个字符串的比较的输出的结果:");
printf("%d\n",cmp);
puts("字符串比较后s1的结果:");
puts(s1);
puts("字符串比较后s2的结果:");
puts(s2);
return 0;
}
题目6:不使用strcmp函数实现两个字符串比较的功能
//不使用strcmp函数实现两个字符串比较的功能
#include<stdio.h>
int main(){
char s1[20]="Hello";
char s2[20]="World!";
int cmp=0,i=0;
while(s1[i]!='\0'||s2[i]!='\0'){
if(s1[i]<s2[i]){
cmp=-1;
break;
}
else if(s1[i]>s2[i]){
cmp=1;
break;
}
i++;
}
if(cmp>0){
puts("s1>s2");
}
else if(cmp<0){
puts("s1<s2");
}
else{
puts("s1==s2");
}
puts("两个字符串的比较的输出的结果:");
printf("%d\n",cmp);
puts("字符串比较后s1的结果:");
puts(s1);
puts("字符串比较后s2的结果:");
puts(s2);
return 0;
}
题目7:使用strlen函数实现测字符串的长度的功能
//使用strlen函数实现测字符串的长度的功能
#include<stdio.h>
#include<string.h>
int main(){
char s[20]="Hello World!";
int len;
len=strlen(s);
puts("测字符串长度后strlen函数的结果:");
printf("%d\n",len);
puts("测字符串长度后s的结果:");
puts(s);
return 0;
}
题目8: 不使用strlen函数实现测字符串的长度的功能
//不使用strlen函数实现测字符串的长度的功能
#include<stdio.h>
int main(){
char s[20]="Hello World!";
int i=0;
while(s[i]!='\0'){
i++;
}
puts("字符串s1的长度是:");
printf("%d\n",i);
puts("测字符串长度后s的结果:");
puts(s);
return 0;
}
题目9:字符串大小写转换
//字符串大小写转换
#include<stdio.h>
#include<string.h>
int main(){
char str1[]="abcdef";
char str2[]="ABCDEF";
strupr(str1);
puts("字符串str1转为小写的输出为:");
puts(str1);
strlwr(str2);
puts("字符串str2转为小写的输出为:");
puts(str2);
return 0;
}