1、介绍
数组可以存放多个同一个类型数据。数组也是一种数据类型,是构造类型。传递是以引用的方式传递(及传递是地址)
2、快速入门
#include <stdio.h>
int main() {
double hens[6];
hens[0]=3;
hens[1]=5;
hens[2]=1;
hens[3]=3.4;
hens[4]=2;
hens[5]=50;
double totalweight=0.0;
double avgweight=0.0;
int i;
int lens=sizeof (hens)/sizeof (double );
for(i=0;i<lens;i++){totalweight+=hens[i];
}
avgweight=totalweight/lens;
int j=sizeof (hens);
printf("鸡的总重量是:%.2f 鸡的平均体重为:%.2f\n",totalweight,avgweight);
printf("sizeof的大小:%d",j);
return 0;
}
改进:
#include <stdio.h>
void main(){
double henss[6]={3,5,1,3.4,2,50};
double sum=0;
double avg=0;
for(int i=0;i<6 ;i++){
sum+=henss[i];
}
avg=sum/6;
printf("这只鸡的总重量为:%.2f 平均体重为:%.2f",sum,avg);
}
3.数组的定义和布局
(1).数组的定义
数据类型 数组名 [数组大小]
int a[5];
赋初值a[0]=1;a[1]=30
(2).说明:
-1.数组名就代表该数组的首地址,即a[0]地址
-2.数组的各个元素是连续分布的,假如:a[0]的地址是0X11122 a[1] 的地址是 0x1122+int字节数=(a[0]的地址+int字节数(4))=0x1122+4=0x1122 a[2]的地址=a[1]的地址+int字节数=0x1126+4=0x112A(十六进制的写法)依次类推
4.数组的使用
(1)定义格式
数组名[下标] 比如:你要使用a数组的第三个元素a[2]
案例:从终端循环输入5个数,保存到double数组,并输出
#include <stdio.h>
void main(){
double arr[5];
int arrlen=sizeof (arr)/sizeof (double);
for(int i=0;i<arrlen;i++){
printf("请输入1个成绩:\n");
fflush(stdout);
scanf("%lf",&arr[i]);
}
for(int j=0;j<arrlen;j++){
printf("arr[%d]=%.2f ",j,arr[j]);
}
getchar();
}
(2).3种初始化数组的方式
void main(){
第一种:
int a[0]=30;
int a[1]=100;
int a[2]=200;
int a[3]=300;
第二种:
int arr[3]={4,5,6}
第三种:如果在定义是时,直接就指定值,可以省略数组的大小
int arr[]={7,8,9,10};
}
5.数组的使用事项和细节
1)数组是多个相同类型的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化。
2)数组创建后,如果没有赋值,则遵守如下规则
全局数组默认值0
非全局数组初值是机器垃圾值(即:原来系统分配给这块空间的值)
3)使用数组的步骤1. 定义数组2. 给数组各个元素赋值 3. 使用数组
4)数组的下标是从0开始的
5)数组下标必须在指定范围内使用,编译通过,在运行时会因为数组越界而异常中断
比如:int arr[5]下标为0~4,数组要特别注意不要越界(且记住小标是从0开始的)
6)C的数组属于构造类型。是引用传递(传递的是地址),因此当把一个数组传递给一个函数时,函数操作数组会影响原数组
案例:
#include <stdio.h>
void f1(int arr[]){
printf("\nf1函数中的arr地址=%p\n",arr);
arr[0]=arr[0]+1;
}
void main(){
int arr[3]={3,4,5};
printf("\nmain函数中的arr地址=%p\n",arr);
int lens=sizeof (arr)/sizeof (int);
f1(arr);
printf("a[0]的值为:%d\n",arr[0]);
for(int i=0;i<lens;i++){
printf("arr[%d]=%d ",i,arr[i]);
}
}
案例题目:
1.创建一个char类型的26个元素的数组,分别放置’A~Z’./使用for循环访问所有的元素并打印出来。提示:字符数据运算’A’+1->‘B’
第一种写法(自己想的)
#include<stdio.h>
void main(){
char arr[26];
arr[0]='A';
int lens=sizeof(arr)/sizeof (char);
for(int i=1;i<lens;i++){
arr[i]=arr[i-1]+1;
}
for(int j=0;j<lens;j++){
printf("arr[%d]=%c ",j,arr[j]);
}
}
第二种写法
#include<stdio.h>
void main03(){
char arr[26];
int lens=sizeof(arr)/sizeof (char);
for(int i=0;i<lens;i++){
arr[i]='A'+i;
}
for(int j=0;j<lens;j++){
printf("arr[%d]=%c ",j,arr[j]);
}
}
2.请求出一个数组的最大值,并得到对应的下标。
#include <stdio.h>
void main(){
int arr[]={1,3000,4,5,6,7800,100};
int max=0;
int a=0;
int lens=sizeof(arr)/sizeof (int);
for(int i=0;i<lens;i++){
if(max<arr[i]){
max=arr[i];
a=i;
}
}
printf("数组元素最大的数是%d,其下标为%d",max,a);
}
6.字符数组与字符串
(1)简单介绍:
1)字符数组基本介绍
用来存放字符的数组称为字符数组,
char a[10];//一维字符串,长度为10
char b[5][10];//二维字符串,5行10列
char c[20]={'c','b','s','f'};//给部分数组元素赋值
字符数组实际上是一系列字符的集合,也就是字符串(String)。在C语言中,没有专门的字符串变量没有String类型,通常就用一个字符数组来存放一个字符串。
2)案例
#include <stdio.h>
void main(){
char c[20]={'t','o','m'};第4个元素是('\0')
printf("%s",c);
}
(2).字符串的注意事项
1)在C语言中,字符串实际上是使用null字符(‘\0’)终止的一维字符数组。因此,一个以null结尾的字符串,包含了组成字符串的字符
2)'\0’是ASCII码表中的第0个字符,用NULL表示,称为空字符。该字符既不能显示也不是控制字符,输出该字符不会有任何效果,他在C语言中仅作为字符串的结束标志。
3)字符数组(字符串)在内存中的布局分析(很重要)
4)思考char str[3]={‘a’,‘b’,‘c’}输出是什么,为什么?char str2[]={‘t’,‘m’,‘o’}输出是什么
答:char str[3]={‘a’,‘b’,‘c’}输出是一堆乱码因为后面的空间没有遇到\0,解决方案,在数组后面人为的加上一个\n
char str[3]={'a','b','c','\0'}就解决问题·了
或者设置数组个数的长度大于3
结论:如果在给某个字符数组赋值时,(1)赋给的元素的个数小于该数组的长度,则会自动在后面加’\0’表示字符串结束。(2)赋给的元素的个数等于该数组的长度,则不会自动在后面加’\0’表示字符串结束。
char str2[]={‘t’,‘m’,‘o’}输出是’tm乱码‘
字符串内存布局图:
(3).字符串的访问和遍历
因为字符串的本质就是字符数组,因此可以按照数组的方式遍历和访问某个元素即可
#include <stdio.h>
void main(){
char greeting[]="Hello";
int i;
int len=sizeof (greeting)/sizeof (char);
printf("\nlen=%d",len);
printf("\n字符串第三个字符是=%c",greeting[2]);
for(i=0;i<len;i++){
printf("\n%c",greeting[i]);
}
}
(4).字符串的表现形式
(1)用字符数组存放一个字符串
1)char str[]=“hello tem”;
2)char str2[]={‘h’,‘e’}
(2)用字符指针指向一个字符串
*比如 : char str =“hello tom”;
1)C语言对字符串常量"hello tom"是按字符数组处理的,在内存中开辟了一个字符数组用来存放字符串常量,程序定义字符串指针变量str时只是把字符串首地址(即存放字符串的字符数组的首地址)赋给str
2)printf(“%s\n”,str);可以输出str指向的字符串
#include <stdio.h>
void main(){
char *pstr ="hello tom";
printf("\n pStr指向的字符串=%s",pstr);
}
使用字符指针变量和字符数组两种方法表示字符串的讨论
1)字符数组由若干个元素组成,每个元素放一个字符;而字符指针变量中存放的是地址(字符串/字符数组的首地址),绝不是将字符串放到字符指针变量中(是字符串的首地址)
2)对字符数组只能对各个元素赋值,不能用以下方法对字符数组赋值
char str[14] 定义的时候就已经开辟了包含14个字符空间的常量,
str="hello tom";
str[0]='i';
3)对字符指针变量,采用下面方法赋值是可以的
char *a;
a="hello tom"
4)如果定义了一个字符数组,那么它有确定的内存地址(即字符数组名是一个常量),而定义的一个字符指针变量时,他并未指向某个确定的字符数据,并且可以多次赋值
#include <stdio.h>
void main(){
char *a="yes";
printf("a本身的地址%p,a指向的地址=%p\n",&a,a);
a="hello tom";
printf("a本身的地址%p,a指向的地址=%p\n",&a,a);
printf("\na=%s\n",a);
}
5)常用字符串函数一览表
函数 | 功能 |
---|
strcpy(s1,s2) | 复制字符串s2到s11,s2 | strcat(s) | 连接字符串s2到字符串s1的末尾1 | strlen(s1) | 返回字符串s1的长度 | strcmp(s1,s2) | 如果s1和s2是相同的,则返回0,如果s1<s2则返回小于0;如果s1>s2则返回大于0; | strchr(s1,ch) | 返回一个指针,指向字符串s1中字符ch的第一次出现的位置 | strstr(s1,s2) | 返回一个指针,指向字符串s1中字符串s2的第一次出现的位置 |
案例实践:
#include<stdio.h>
#include <string.h>
void main(){
char str1[12]="Hello";
char str2[12]="World";
char str3[12];
int len;
strcpy(str2,str1);
printf("strcpy(str2,str1)后str2的值为: %s\n",str2);
strcat(str1,str2);
printf("strcat(str1,str2)连接之后: %s\n",str1);
len=strlen(str1);
printf("strlen(str1):拼接后的长度%d\n",len);
}
10、字符串(字符数组)使用注意事项和细节
1)程序中往往依靠检测’\0’的位置来判定子字符串是否结束,而不是根据数组的长度来决定字符串长度。因此,字符串长度不会统计’\0’,字符数组的长度会统计
2)在定义字符数组应估计实际字符串长度,保证数组长度始终大于字符串实际实际长度,否则,在输出字符数组时可能出现未知字符。
3)系统对字符串常量也自动加一个’\0’作为结束符。例如"C Program”共有9个字符,但在内存中占10个字节,最后一个字节’\0’是系统自动加上去的。(通过sizeof()函数即可)
4)定义字符数组时,如果给的字符个数比数组的长度小,则系统会默认将剩余的元素空间全部设置为’\0’,比如char str[6]=“ab”,str内存布局就是[a] [b] [\0] [\0] [\0] [\0]
5)字符数组定义和初始化的方式比较多,比如
char str1[]={“I am happy”};//默认后面加’\0’
char str2[]="I am happy ";//省略{}号,默认后面加上’\0’
char str3[]={‘i’,’ ‘,‘a’,‘m’,’ ‘,‘h’,‘a’};//字符串数组后面不加’\0’可能有乱码
char str4[5]={‘i’,’ ‘,‘a’,‘m’,’ ‘,‘h’,‘a’};//字符数组后面不加’\0’,可能有乱码
char *str=“hello world”;
#include<stdio.h>
void main(){
char str1[]={"I am happy"};
char str2[]="I am happy ";
char str3[]={'i',' ','a','m',' ','h','a'};
char str4[5]={'i',' ','a','m',' ','h','a'};
char *str="hello world";
printf("\nstr1=%s",str1);
printf("\nstr2=%s",str2);
printf("\nstr3=%s",str3);
printf("\nstr4=%s",str4);
}
正误判断
char str[];
str="I am happy";
7、冒泡排序
冒泡排序:冒泡排序的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡一样逐渐向上看
因为排序的过程中,各元素不断接近自己的位置,如果下一趟比较下来没有进行交换,就说明序列有序。因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较。
案例:
有5个无序的数:{3.9.-1.10.-2}我们使用冒泡排序将其从小到大进行排序操作
过程:
第一轮
(1):3,9,-1,10,-2
(2):3,-1,9,10,-2
(3):3,-1,9,10,-2
(4):3,-1,9,-2,10 //第一大的数就移动到最后
第二轮
(1):-1,3,9,-2,10
(2): -1,3,9,-2,10
(3):-1,3,-2,9,10//第二轮经过3次比较移动到适当的位置
第三轮排序
(1):-1,3,-2,9,10
(2) :-1,-2,3,9,10//第三轮经过2次比较将大的数找到合适的位置
第四轮排序
(1):-2,-1,3,9,10:排序结束
代码实现:
#include <stdio.h>
void main()
{
int arr[]={3,9,-1,10,-2};
int j;
int i;
int t;
for(j=0;j<4;j++){
if(arr[j]>arr[j+1]){
t=arr[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
for(j=0;j<5;j++){
printf("%d ",arr[j]);
}
for(j=0;j<3;j++){
if(arr[j]>arr[j+1]){
t=arr[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
printf("]\n");
for(j=0;j<5;j++){
printf("%d ",arr[j]);
}
for(j=0;j<2;j++){
if(arr[j]>arr[j+1]){
t=arr[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
printf("\n");
for(j=0;j<5;j++){
printf("%d ",arr[j]);
}
for(j=0;j<1;j++){
if(arr[j]>arr[j+1]){
t=arr[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
printf("\n");
for(j=0;j<5;j++){
printf("%d ",arr[j]);
}
}
改进后的代码:
#include <stdio.h>
void main(){
int i;
int j;
int t;
int arr[]={-1,2,-3,3,7,8,1};
int len=sizeof (arr)/sizeof(int);
printf("%d\n",len);
for(i=0;i<len-1;i++){
for(j=0;j<len-1-i;j++) {
if (arr[j] > arr[j + 1]) {
t = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = t;
}
}
}
for(i=0;i<len;i++){
printf("%d ",arr[i]);
}
}
8、查找
1)介绍
在C中,我们常用的查找有两种:
(1)顺序查找
(2)二分查找
2)案例演示:
1)有一个数组:{23,1,34,89,100}
猜数游戏:从键盘中任意输入一个数,判断数列中是否包含该数【顺序查找】
要求:如果找到了,就提示找到,并给出下标值,找不到提示 没有。
#include <stdio.h>
int seqSeach(int arr[],int arrLen,int val){
int i;
for(i=0;i<arrLen;i++){
if(arr[i]==val) {
return i;
}
}
return -1;
}
void main(){
int arr[]={1,34,78,12,35,9};
int len=sizeof (arr)/sizeof (int);
int a=seqSeach(arr,len,9);
if(a!=-1){
printf("找到了\n");
}else{
printf("no find it\n");
}
printf("该数的下标为:%d\n",a);
}
2)请对一个有序组进行二分查找 {1,8,89,1000,1234},输入一个数看看看该数是否存在此数,并且求出下标,如果没有就提示“没有这个数”,二分查找的前提是有序的数组
#include <stdio.h>
int binarySearch(int arr[],int leftIndex,int rightIndex,int findVal ){
if(leftIndex>rightIndex){
return -1;
}
int midIndex=(leftIndex+rightIndex)/2;
int midVal=arr[midIndex];
if(midVal>findVal){
binarySearch(arr,leftIndex,midIndex-1,findVal);
}else if(midVal<findVal){
binarySearch(arr,midIndex+1,rightIndex,findVal);
}else{
return midIndex;
}
}
void main(){
int arr[]={1,8,10,89,1000,1234};
int arrLen=sizeof (arr)/sizeof (int);
int index=binarySearch(arr,0,arrLen-1,1000);
if(index !=-1) {
printf("找到了index=%d", index);
}else{
printf("没有找到");
}
}
9、多维数组—二维数组
1)了解
二维i数组应用场景: 开发一个五子棋游戏,棋盘就是需要二维数组来表示。
2)案例:
请使用二维数组输出如下图形
0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0
#include <stdio.h>
void main(){
int a[4][6];
int i,j;
for(int i=0;i<4;i++){
for(int j=0;j<6;j++){
a[i][j]=0;
}
}
a[1][2]=1;
a[2][1]=2;
a[2][3]=3;
for( i=0;i<4;i++){
for(j=0;j<6;j++){
printf("%d ",a[i][j]);
}
printf("\n");
}
printf("\n二维数组a的首地址为%p",a);
printf("\n二维数组a[0]的地址为%p",a[0]);
printf("\n二维数组a[0][0]的地址为%p",&a[0][0]);
printf("\n二维数组a[0][1]的地址为%p",&a[0][1]);
printf("\n二维数组a[0][2]的地址为%p",&a[0][2]);
printf("\n");
for(i=0;i<4;i++){
printf("a[%d]的地址=%p ",i,a[i]);
for(j=0;j<6;j++){
printf("a[%d][%d]的地址=%p ",i,j,&a[i][j]);
}
printf("\n");
}
}
0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0
使用方式2直接初始化:
-2.定义 类型 数组名 [size] [size]={{值1,值2…},{值1,值2…},{值1,值2…}}
或者类型 数组名 [size] [size]={值1,值2,值3,值4,值5,值6…}=
-3.遍该数组map[3][3]={{0,0,1},{1,1,1},{1,1,3}};
第一种方式:
#include <stdio.h>
void main(){
int map[3][3]={{0,0,1},{1,1,1},{1,1,3}};
int sum=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
printf("map[%d][%d]=%d ",i,j,map[i][j]);
sum+=map[i][j];
}
printf("\n");
}
printf("sum=%d",sum);
}
第二种方式:
#include <stdio.h>
void main(){
int map[3][3]={{0,0,1},{1,1,1},{1,1,3}};
int rows =sizeof (map)/sizeof (map[0]);
int cols=sizeof (map[0])/sizeof (int);
int i,j;
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
printf("%d ",map[i][j]);
}
printf("\n");
}
题二、
#include <stdio.h>
void main(){
double score[3][5];
int rows=sizeof (score)/sizeof (score[0]),cols=sizeof (score[0])/sizeof (double),i,j;
double totalscore =0.0,classTotalScore=0.0;
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
score[i][j]=0.0;
}
}
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
printf("请输入第%d个班的第%d个学生的成绩: ",i+1,j+1);
fflush(stdout);
scanf("%lf",&score[i][j]);
}
}
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
printf("%.2f",score[i][j]);
}
printf("\n");
}
for(i=0;i<rows;i++){
classTotalScore=0.0;
for(j=0;j<cols;j++){
classTotalScore+=score[i][j];
}
printf("\n第%d个班的平均成绩是 %.2f",i+1,classTotalScore/cols);
totalscore+=classTotalScore;
}
printf("\n所有学生的总成绩是%.2f平均成绩是%.2f",totalscore,totalscore/(rows*cols));
}
3)、二维数组使用细节和注意事项
-
可以只对部分元素赋值,为赋值的元素自动取"零"值 -
如果对全部元素赋值,那么第一维的长度可以不给出比如: int a[3][3]={1,2,3,4,5,6,7,8,9}
可以写为int a[][3]={1,2,3,4,5,6,7,8,9}
-
二维数组可以看作是由一维数组嵌套而成的;如果一个数组的每个元素又是一个数组,那么可以看作就是二维数组 二维数组a[3][4]可看作三个一维数组,他们的组名分别是a[0],a[1],a[2]
这三个一维数组都有4个元素,如,一维数组a[0]的元素有:a[0][0],a[0][1],a[0][2],a[0][4]
printf("%.2f",score[i][j]);
}
printf("\n");
} //统计各个班的总成绩,和所有学生的总成绩 for(i=0;i<rows;i++){ classTotalScore=0.0;//换班的时候将班级总成级重新赋值为0.0 for(j=0;j<cols;j++){ classTotalScore+=score[i][j]; } printf(“\n第%d个班的平均成绩是 %.2f”,i+1,classTotalScore/cols); totalscore+=classTotalScore;//将各个班的成绩进行累加 } printf(“\n所有学生的总成绩是%.2f平均成绩是%.2f”,totalscore,totalscore/(rows*cols));
}
#### 3)、二维数组使用细节和注意事项
1. 可以只对部分元素赋值,为赋值的元素自动取"零"值
2. 如果对全部元素赋值,那么第一维的长度可以不给出比如:
int a[3][3]={1,2,3,4,5,6,7,8,9} 可以写为int a[][3]={1,2,3,4,5,6,7,8,9}
3. 二维数组可以看作是由一维数组嵌套而成的;如果一个数组的每个元素又是一个数组,那么可以看作就是二维数组
二维数组a[3][4]可看作三个一维数组,他们的组名分别是a[0],a[1],a[2] 这三个一维数组都有4个元素,如,一维数组a[0]的元素有:a[0][0],a[0][1],a[0][2],a[0][4]
|