【C语言】六、数组(一维&二维)

6.1 一维数组

6.1.1 定义

  • 格式:数据类型 数组名[常量表达式]
  • 说明:
    • 一个数组名在程序中只能说明一次,不能重复说明。
    • 常量表达式定义了数组元素的个数。
    • 常量表达式可以是整数常量、符号常量或常量表达式,不能包含变量,其值必须是正整数

存放方式

  • 总字节数:sizeof(类型)*数组长度=总字节数 (可以用printf("%d",sizeof(a));来读每个类型的sizeof,但是sizeof还不太懂!!)
  • 再不理解看这里:C语言基础——sizeof的用法总结。之后要自己总结一下。

6.1.2 引用

数组元素都是变量

  • 只能逐个引用数组中的数组元素,不能一次引用整个数组;
  • 引用方式:数组名[下标]
    • 下标可以是整数、符号常数、变量或整型表达式;
    • 对于长度为n的数组,下标范围为0~(n-1)。
int c[10];
c[0]=3;
scanf("%d",&c[1]);
printf("%d %d",c[0],c[1]);

引用规定

  1. 数组必须先定义后使用;
  2. 对数组中所有元素逐个引用时,通常使用循环结构;
int i,a[10];
for(i=0;i<10;i++)
   a[i]=i;

赋值

  1. 用赋值语句;2.用输入函数;3.定义数组时对数组元素赋初值。
例:数组的输入与输出
#inlcude<stdio.h>
int main()
{ int i,a[5];
  for(i=0;i<=4;i++)  //输入的时候是从左往右走的
    scanf("%d",&a);
  for(i=4;i>=0;i--)
    printf("a[%d]=%d ",i)   //输出的时候是从右往左走的
}

运行
输入:1 2 3 4 5
输出:a[4]=5 a[3]=4 a[2]=3 a[1]=2 a[0]=1

6.1.3 初始化

  • 定义时完成赋值任务;
  • 格式:数据类型 数组名[表达式]={初值表};
  • 给全部元素赋初值;
    • 数组的长度就是初值表中数值的个数;
    • 如果数组长度与初始数据个数不相等,在定义数组时不能省略数组长度;
  • 给部分元素赋初值(剩下的元素初值都是0);
  • 说明:没有初始化的数组,其元素值不确定(可以是任意值);
例:显示FIbonacci数列前40项。
#include<stdio.h>
int main()
{ int i,fibo[40]={1,1};
  for(i=2;i<40;i++)
    fibo[i]=fibo[i-1]+fibo[i-2];
  for(i=0;i<40;i++)
  { printf("%10d",fibo[i]);
    if((i+1)%5==0)
    printf("\n");
  }
}

6.1.4 应用

例:已有10个数,求其中的最大值。
#include<stdio.h>
int main()
{ int i,max,a[10]={8,2,3,4,5,1,0,85,32,54},k;  //k:显示最大值位于第几个
  max=a[0];
  k=0;
  for(i=0;i<10;i++)  //注意for循环条件中间隔符号是;不是, 
    if(a[i]>max)
	{ max=a[i];
	  k=i;}
  printf("max=%d %d\n",max,k);
  return 0; 
 } 

排序

数据排序(按特定的顺序来安排数据)是最重要的计算应用之一。
常用的方法:冒泡排序;选择排序;直接插入排序;

冒泡法(起泡法)排序
  • 思路:将相邻两个数进行比较,小数放在前头,大数放在后头。先将第一个元素与第二个元素比较,若数值按递增排列就保持原样, 否则两者交换,然后比较第二个元素和第三个元素,依次类推。这样在第一轮扫描结束后, 使最大的元素被安置到最后一个位置上。第二轮扫描再对n-1个元素重复以上过程。(n个数需要n-1轮扫描)
1)a[j]≤a[j+1]时,保持原样;
(2)a[j]≥a[j+1]时,进行交换,保证a[j]为较小数。
  • 分析说明:
    • 将待排序的数据(13,76,97,65,38,49)放入一维数组中;
    • 相邻两数比较:a[j]>a[j+1]进行交换,保证a[j]为较小的数。
    • 第一轮:6个数,j=0 ~ 4,循环5次,找出最大数,放在最后。(诶,有点想不明白,为什么是0-4)(噢噢,明白了,因为j=4的时候是a[4]和a[5]在比较,就已经完成了所有数的比较)
    • 第二轮:5个数,j=0 ~ 3,循环4次,找出次大数,放在最大数前。
    • 以此类推,经过5轮,将6个数排序输出。
    • 所以:外循环为i=0 ~ 4,内循环为:j=0 ~ 4-i
for(i=0;i<5;i++)  //循环次数
    for(j=0;j<5-i;j++)  //数组内的数
        if(a[j]>a[j+1])
        { a[j]=a[j+1] }

图解示例

例:用冒泡法对任意10个数按由小到大的方式排序。
#include<stdio.h>
#define N 10
int main()  //主函数 
{ int a[N],i,j,t;
  printf("请输入10个整数:\n");  //3 4 5 6 89 0 3 6 8 45
  for(i=0;i<N;i++)  //键入10个数,放入a数组中 
    scanf("%d",&a[i]);
	printf("\n");
  for(i=0;i<N-1;i++)  //冒泡排序,比较的轮数 
    for(j=0;j<N-1;j++)  //比较一轮 
       if(a[j]>a[j+1])  //比较一次 
	   { t=a[j]; a[j]=a[j+1]; a[j+1]=t;}
  printf("按有小到大的顺序输出10个整数是:\n"); 
  for(i=0;i<N;i++)
  printf("%d ",a[i]);
  return 0;   
}
选择法排序
  • 排序过程:
    • 首先通过n-1次比较,从n个数中找出最小的,将它与第一个数交换——第一趟选择排序,结果最小的数被安置在第一个元素位置上;
    • 再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,将它与第二个数交换——第二趟选择排序;
    • 重复上述过程,共经过n-1趟排序后,排序结束。
  • 对数组元素a[0]~a[6]升序排序初始:[49 38 65 97 76 13 27]
流程
i=0 一轮:找a[0]至a[6]的最小值,与a[0]交换其值 13 [38 65 97 76 49 27]
i=1 二轮:找a[1]至a[6]的最小值,与a[1]交换其值 13 27 [65 97 76 49 38]
i=2 三轮:找a[2]至a[6]的最小值,与a[2]交换其值 13 27 38 [97 76 49 65]
i=3 四轮:找a[3]至a[6]的最小值,与a[3]交换其值 13 27 38 49 [76 97 65]
i=4 五轮:找a[4]至a[6]的最小值,与a[4]交换其值 13 27 38 49 65 [97 76]
i=5 六轮:找a[5]至a[6]的最小值,与a[5]交换其值 13 27 38 49 65 76 [97]
for(i=0;i<6;i++) 
&emsp;for(j=i+1;j<7;j++)
    &emsp;&emsp;循环体
    &emsp;&emsp;比较a(i)a(j)
    &emsp;&emsp;a(i)大于a(j)
    &emsp;&emsp;a(i)a(j)交换值

例:用选择排序法对10个数从小到大排序。
方法一:
#include<stdio.h>
#define N 10
int main()
{ int i,j,t,a[N]={1,3,46,8,34,88,92,15,9,11};  //i,j,t三个变量的用处
  for(i=0;i<N-1;i++) //前一项
    for(j=i+1;j<N;j++)  //后一项
      if(a[i]>a[j])  //两者对比,使用循环体
      { t=a[i];a[i]=a[j];a[j]=t;}  //将小的数放在前面
  printf("从小到大排序:"); 
  for(i=0;i<N;i++)
    printf("%d ",a[i]);
  return 0;
} 
方法二:
#include<stdio.h>
int main()
{ int i,j,k,x,a[10]={1,3,46,8,34,88,92,15,9,11};
  for(i=0;i<9;i++)
  { k=i;  
    for(j=i+1;j<10;j++)
      if(a[j]<a[k])
      k=j;  //找出最小值,直接与a[i]比较,交换次数减少
    if(i!=k)
    { x=a[i];a[i]=a[k];a[k]=x; }
  }
  printf("从小到大排序:");
  for(i=0;i<10;i++)
    printf("%d ",a[i]); 
  return 0;
}

运行结果:
从小到大排序:1 3 8 9 11 15 34 46 88 92

两种方法比较

插入法排序

向有序数组中插入一个整数x。假定有是个整数按由小到大的顺序放在a数组中,待插入的数放在x中,x的值为30。
在这里插入图片描述

关键代码:
(1)                   (2)
p=0;                   for(i=10;i>p;i--)
while(x>[p]&&p<=9)        a[i]=a[i-1];
   p=p+1;              a[p]=x;

完整代码:
#include<stdio.h>
#define N 11
int main()
{ int a[N]={14,25,28,33,45,56,68,72,81,95};  
  int i,x,p=0;
  printf("请输入x:");
  scanf("%d",&x);
  while(x>a[p]&&p<=9)
    p++;  //找到插入点 
  for(i=10;i>p;i--)
    a[i]=a[i-1];  //将位置腾出 
  a[p]=x;  //插入数据 
  for(i=0;i<N;i++)
  printf("%d ",a[i]);
  printf("\n"); 
}

用插入法对数进行排序

例:对10个数从小到大排序。
#include<stdio.h>
#define N 10
int main()
{ int a[N]={11,8,4,7,9,1,12,14,6,2};
  int i,j,t,n;
  n=sizeof(a)/sizeof(int);  //这个有什么用呢? 
  for(i=1;i<n;i++)  //循环开始,直到型。先判断,再执行,可能一次也不执行 
  { t=a[i];  //第一个是a[1]=8 
    for(j=i-1;j>=0&&t<a[j];j--)  //将数与前一个比较,如果更小就放到前面 
      a[j+1]=a[j];  //符合条件继续交换 
    a[j+1]=t;  //进行交换 
  }  
  for(i=0;i<n;i++)
  printf("%d ",a[i]);
  return 0;
} 

6.2 二维数组

6.2.1 定义

  • 二维数组是由具有两个下标的数组元素组成。
  • 格式:数据类型数组名[常量表达式1][常量表达式2]——其中表达式1表示行,表达式2表示列
  • 如:int a[3][4]
0列1列2列3列
0行a[0][0]a[0][1]a[0][2]a[0][3]
1行a[1][0]a[1][1]a[1][2]a[1][3]
2行a[2][0]a[2][1]a[2][2]a[2][3]

存储方式

  • 二维数组的元素是按行存放的。
  • 如:int a[3][4]
  • 二维数组的字节总数:行数×列数×类型字节数 = 总字节数
    在这里插入图片描述

6.2.2 引用

  • 引用格式:数组名[行下标][列下标]
int a[3][4];
for(m=0;m<3;m++)
   for(n=0;n<4;n++)
      printf("%d",a[m][n]);

6.2.3 初始化

  • 通常是按行进行赋值。
  • 格式:数据类型 数组名[表达式1][表达式2]={初值表}
  • 三种方式:
    • 全部元素赋初值;如,int x[2][4]={{1,2,3,4},{6,7,8,9}};(用括号按行分组)或写成int x[2][4]={1,2,3,4,6,7,8,9};
    • 部分元素赋初值;如,int a[3][4]={1,2,3,4,5);(剩余没有明确初始化的元素被自动初始化
      ( 1 2 3 4 5 0 0 0 0 0 0 0 ) \begin{pmatrix} 1 & 2 &3 & 4 \\ 5 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ \end{pmatrix} 150200300400 【开始学习LaTex数学公式,附上两个链接:LaTeX数学符号总结(jupyter notebookLaTeX 中插入数学公式CSDN 中利用 LaTex 插入数学公式Cmd Markdown 公式指导手册
    • 可用分行赋值的方法对某行中部分元素赋初值;如, inta[3][4]={{1},{5},{6}};
      ( 1 0 0 0 5 0 0 0 6 0 0 0 ) \begin{pmatrix} 1 & 0 &0 & 0 \\ 5 & 0 & 0 & 0\\ 6 & 0 & 0 & 0\\ \end{pmatrix} 156000000000
    • 全部元素赋初值时,不指定第一维的长度,但要指定第二维的长度。
    • 省略第一维的长度时,也可对部分元素赋初值,但应分行赋值。如,int a[][4]={{1,2,3},{0},{0,10}};
      ( 1 2 3 0 0 0 0 0 0 10 0 0 ) \begin{pmatrix} 1 & 2 &3 & 0 \\ 0 & 0 & 0 & 0\\ 0 & 10 & 0 & 0\\ \end{pmatrix} 1002010300000

6.2.4 应用

例:给一个2*3的二维数组各元素赋值,并输出全部元素的值。
#include<stdio.h>
#define Row 2
#define Col 3
int main()
{ int i,j,a[Row][Col];   /*定义1个2行3列的2维数组array*/ 
  printf("Input a[%d][%d]:\n",Row,Col); 
   for(i=0; i<Row; i++)	/*外循环:控制2维数组的行*/
      for(j=0; j<Col; j++)  	/*内循环:控制2维数组的列*/    
	  { 
        scanf("%d",&a[i][j]);     /*从键盘输入a[i][j]的值*/
      }
  for(i=0;i<Row;i++) 
  { 
    for(j=0;j<Col;j++)
    printf("%d ",a[i][j]);    /*将a[i][j]的值显示在屏幕上*/
    printf("\n");
  }
  return 0;
}

求矩阵转置

  • 分析:将一个二维数组a行和列元素互换后,存到另一个二维数组b中。
    a = [ 1 2 3 4 5 6 ] a=\begin{bmatrix} 1 & 2 & 3\\ 4 & 5 & 6 \\ \end{bmatrix} a=[142536]               b = [ 1 2 3 4 5 6 ] b=\begin{bmatrix} 1 & 2 & 3\\ 4 & 5 & 6 \\ \end{bmatrix} b=[142536]
  • 关系:a[ i ] [ j ]==b[ j ] [ i ]
  • 实现:b[ j ] [ i ] =a[ i ] [ j ]
for(i=0;i<2;i++)
   for(j=0;j<3;j++)
      b[j][i]=a[i][j]

完整代码:
#include<stdio.h>
int main()
{ int a[2][3]={{1,2,3},{4,5,6}},b[3][2],i,j;
  printf("输出转置前的数组:\n");
  for(i=0;i<2;i++)
  { for(j=0;j<3;j++)
      { printf("%5d",a[i][j]);
           b[j][i]=a[i][j];  //进行转置
	  }
	  printf("\n");
  }
  printf("输出转置后的数组:\n");
  for(i=0;i<3;i++)
    { for(j=0;j<2;j++)
        printf("%5d",b[i][j]);  //注意输出的行列数
      printf("\n");
	}
  return 0; 
}

Q1:代码编译的时候结果无法输出,调试的时候成功输出,为什么呢?
编译结果
调试结果

6.3 字符数组与字符串

6.3.1 定义与初始化

定义

  • 定义:用来存放字符型数据的数组。在字符数组中,每个数组元素只能存放一个字符。
  • 格式:
    • char 数组名[常量表达式];
    • char 数组名[常量表达式1][常量表达式2];

初始化

  • 字符常数初始化数组。例,char c[8]={‘c’,‘h’,‘i’,‘n’,‘a’};
    • 若字符个数>数组长度,则作错误处理;
    • 若字符个数<数组长度,则将这些字符赋给前面的元素,其余元素自动为空字符==(’\0’)==.
    • 存储形式:
c[0]c[1]c[2]c[3]c[4]c[5]c[6]c[7]
‘c’‘h’‘i’‘n’‘a’‘\0’‘\0’‘\0’
  • 字符串为字符数组赋初值。例,char a[6]={“china”}; 或 char a[6]=“china”;
    • c语言中所有字符串都是一’\0’结束。
    • 存储形式:存储形式
  • *用字符串为字符数组赋初值比用字符常数赋值时要多占一个字节。用字符初始化时,不要求最后一个字符一定为’\0’。
    • char c[5]={‘c’,‘h’,‘i’,‘n’,‘a’};
    • char c[6]=“china”;
四种表示方式
char s1[10]={‘C’,’-’,‘P’,‘r’,‘o’,‘g’,‘r’,‘a’,‘m’};
char s2[10]={“C-Program”};
char s3[10]={“C-Program”};
char s4[]=“C-Program”;
  • 存储形式:
    存储形式
  • 对二维字符数组可以看作是一维字符串数组。char str[3][6] //包含3个字符串的数组
    • 初始化:char str[3][6]={“wang”,“zhang”,“li”};
    • 存储形式:在这里插入图片描述
      printf("%s%s",&str[0][0],&str[1][3]);

6.3.2 输入与输出

  • 逐个字符输入输出 %c
#include<stdio.h>
int main()
{ int i;char a[6];
  for(i=0;i<6;i++)
    scanf("%c",&a[i]);  //a[i]=getchar()
  for(i=0;i<6;i++)
    printf("%c",a[i]);
  printf("\n");
  return 0;
}
  • 作为整体一次输入输出 %s
#inlcude<stdio.h>
int main()
{ char a[6];
  scanf("%s",&a[0]);   //数组名代表数组的首地址
  printf("%s",a);
  printf("\n");
  return 0;
}
 - scanf函数参数要求的是地址,故直接用字符数组名进行操作;
 - 输出字符不包括结束符'\0';
 - 用%s格式输出字符串时,输出项只能是字符数组名,不能是数组元素名。printf("%s\n",a[0]);
 - %s输入字符串时,遇空格、回车符、Tab结束输入,不能接收空格。
 	-若 char c1[6],c2[6];
 	    scanf("%s%s",c1,c2);
 	 输入:a good book
 	      printf("%s %s\n",c1,c2);
 	 输出:a good

存储

 - 若一个字符数组中含有一个或多个“\0”,则遇到第一个“\0”时结果输出。
#include<stdio.h>
int main()
{ char a[10]={"Boy\0abc"};
  printf("%s",a);
  printf("\n");
  return 0;
} 

输出结果:Boy
  • 用字符串输入输出函数 gets() ; puts()
字符串输入函数字符串输出函数
格式gets(字符数组名)puts(字符数组名);或puts(字符串);
作用将输入的字符串给字符数组。输入时,遇第一个回车符结束输入。可接收空格、制表符输出字符数组的值,遇’\0’结束输出。
注意(1)gets()函数同scanf()函数一样,在读入一个字符串后,系统自动在字符串后加上一个字符串结束表示’\0’。(2)函数gets()只能一次输入一个字符串。(1)puts()一次只能输出一个字符串。输出字符串后自动换行。可以输出转义字符。(2)printf()函数可以同时输出多个字符串,并且能灵活控制是否换行,所以printf()函数比puts()函数更为常用。
例:函数gets()scanf()的区别。
#inlcude<stdio.h>
int main()
{ char str1[20],str2[20];
  gets(str1);
  scanf("%s",str2);
  printf("str1:%s\n",str1);
  printf("str2:%s\n",str2);
  return 0;
}

输入: program C
      program C
输出:str1:program C
     str2:program
例:函数puts()printf()的区别
#include<stdio.h>
int main()
{ char str1[]="student",str2[]="teacher";
  puts(str1);
  puts(str2);
  printf("%s",str1);  //为什么输出会是两个student
  printf("%s\n%s",str1,str2);
  return 0;
}

输出结果:
student
teacher
studentstudent
teacher

6.3.3 字符串处理函数

  • #inlcude “string.h”

字符串连接函数strcat

  • 格式:strcat(字符数组1,字符数组2);
  • 作用:连接两个字符数组中的字符串,将字符串2连接到字符数组1的后面,结果放在字符数组1中。
  • 例:char a[15]=“Hello”;
      stract(a," world");
      printf("%s",a);
      输出:Hello world
  • 字符数组1的’\0’将被字符串2覆盖,连接后生成的新的字符串的最后保留一个’\0’。
    存储变化

字符串拷贝函数strcpy

  • 格式:strcpy(字符数组1,字符串2);
  • 作用:将字符串2拷贝到字符数组1中。只复制第一个’\0’前的内容(含’\0’)。
  • 例:char a[20]=“Hello”;
      strcpy(a,“world”);
      printf("%s",a);
      输出:world
    Q:怎么看输出?

测字符串长度函数strlen

  • 格式:strlen(字符串);
  • 作用:返回字符串中有效字符的个数,不包括结束符’\0’。
  • 例:char str[10]=“abcdefgh”;
      printf("######%d\n",strlen(str));
      输出:######8

字符串比较函数strcmp

  • 格式:strcmp(字符串1,字符串2);
  • 作用:比较字符串2和字符串2
    • 字符串1==字符串2,函数返回值为0;
    • 字符串1>字符串2,函数返回值为1;
    • 字符串1<字符串2,函数返回值为-1;
    • printf("####%d\n",strcmp(“b”,“b”)); 输出####0
    • printf("####%d\n",strcmp(“b”,“f”));输出####-1
  • 注意
    • 对两个字符串比较,不能用以下形式:if(str1==str2) printf(“yes”);
    • 只能用:if (strcmp(str1,str2)==0) printf(“yes”);
例:用户登录。
#include<stdio.h>
#include<string.h>
int main()
{ char username[10],name[10]="zhang";
  gets(username);
  if(strcmp(username,name))
    printf("Username are wrong!\n");
  else
    printf("You are right!\n");
  puts(username);
  return 0;
}

字符串处理函数strlwr、strupr

  • strlwr(字符数组名);lower
  • 作用:将字符数组中大写字母转换成小写字母
  • strupr(字符串);upper
  • 作用:将字符数组中小写字母转换成大写字母
  • 例:char a[20]=“Hello”;
      printf("%s,%s",strlwr(a),strupr(a));
      输出:hello,HELLO

6.3.4 字符数组应用

例:任意输出两个字符串,将它们连接成一个字符串,不使用strcat函数。
#include<stido.h>
int main()
{ char s1[100],s2[40];
  int i=0,j=0;
  scanf("%s",s1);
  scanf("%s",s2);
  while(s1[i]!='\0')
    i++;  //i值不断增1,直到遇到\0为止
  while(s2[j]!='\0')  //将字符串2的字符复制到字符串1后面
    s1[i++]=s2[j++];
  s1[i]='\0';  //人为加上字符串结束标志
  printf("\nlinked string:%s,s1);
  return 0;
例:打印图案。
方法一:
#include<stdio.h>
int main()
{ int i,j;
  char a[]={'*','*','*','*'},space=' ';
  for(i=0;i<5;i++) //打印图案,共5行
  { for(j=1;j<=2*i;j++)  //打印每行图案前的空格
      printf("%c",space);  //%c表示字符型格式符;%s表示字符串型格式符
    for(j=0;j<5;j++)  //打印每行图案
      printf(“%2c“,a[i];
    printf("\n");
  }
}
 方法二:
 #include<stdio.h>
 int main()
 { char tx[]="*****";
   int i,j;
   for(i=1;i<=5;i++)
   { for(j=1;j<i;j++)
       printf(" ");
     printf("%s\n",tx);
   }
   return 0;
 }
 输出结果:
 *****
  *****
   *****
    *****
     *****
例:字符数组的整体输入与输出。
#inlcude<stdio.h>
int main()
{ int i;
  char name[5][9]={"Tom","John","Mary","Joe","Jonson"};
  for(i=0;i<5;i++)
    printf("\n%s\t",name[i]);  //name[i]代表该行数组元素的首地址
  getch();
}
例:有三个字符串,要求找出其中最大者。设有一个二维的字符数组str,大小为3×20。即有320列,每一行可以容纳20个字符。如:
str[0]:China\0
str[1]:japan\0
str[2]:india\0
程序如下:
#include<stdio.h>
int main()
{ int i;
  char string[20],str[3][20];
  for(i=0;i<3;i++)
  gets(str[i]);
  if(strcmp(str[0],str[1])>0)strcpy(string,str[0]);
  else strcpy(string,str[1]);
  if(strcmp(str[2],string)>0)strcpy(string,str[2]);
  printf("\n the largest string is: %s\n",string);
}
例:输入一行字符,统计其中有多少个单词,单词之间用空格分隔。
算法:逐一检测字符,遇到第一个非空格字符即为一个新单词的开始,再次遇到空格就表示单词结束,
定义一个标记变量word
记住当前字符的前一个字符(最近检测的)是否是空格。
- 最近检测的字符是空格,word=0
- 最近检测的字符不是空格,word置1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值