Day08
睡不着…
纠正Day07的错误
数组可以动态定义
代码案例
#include <stdio.h>
int main()
{
int i,n;
printf("请输入一个常数\n");
scanf("%d",&i);
char a[i+1];
printf("请开始输入字符\n");
for(n=0;n<i;n++)
{
scanf("%c",&a[n]);
}
a[i]='\0';//数组不会自动添加'\0',要主动去设置,这样才能输出字符串
printf("你输入的字符串是;%s\n",a);
return 0;
}
在C99的数组标准中,有这样一句话,数组的尺寸如果是整型常量或整型常量表达式,或已确定数组尺寸时,
那么这个数组的类型不是一个可变长度的数组,否则,它就是可变数组
但是仍然存在一个问题,这行代码的输出结果:
请输入一个常数
3
请开始输入字符
abc
你输入的字符串是;
ab
会发现输出的字符比输入的字符少一位
原因:在使用第一个scanf函数时,按下了换行符,此时换行符就被保留在缓冲区内,下一个scanf读取到的第一个字符其实是换行符。
修改后:
#include <stdio.h>
int main()
{
int i,n;
printf("请输入一个常数\n");
scanf("%d",&i);
getchar()//用来读取输入的换行符
char a[i+1];
printf("请开始输入字符\n");
for(n=0;n<i;n++)
{
scanf("%c",&a[n]);
}
a[i]='\0';//数组不会自动添加'\0',要主动去设置,这样才能输出字符串
printf("你输入的字符串是;%s\n",a);
return 0;
}
数组的边界可以访问
#include <stdio.h>
int main()
{
int i;
int a[10];
for(i=0;i<=10;i++)//故意写成这样引起数组越界问题
{
a[i]=i;
}
for(i=0;i<=10;i++)
{
printf("%d",a[i]) ;
}
return 0;
}
输出结果:
012345678910
奇怪之处:十一号元素可以输出
添加一句a[10]=111,仍然可以解决
可能新版的编译器对数组越界问题建立的保护机制,但最好不要这样做
字符数组
保存字符串的方式:
- 字符串常量
- 字符数组
字符串初始化
int main()
{
char a[]={'H','0','D','1','N','\0'};//不写元素个数,编译器会自动计算
char b[]={"H0D1N"};//可以使用字符串常量初始化
char c[]="H0D1N"//使用字符串常量初始化可以省略大括号
}
字符串处理函数
使用字符串处理函数需要加上头文件**#include <string.h>**
- 获取字符串的长度:strlen
#include <stdio.h>
#include <string.h>
int main()
{
char a[]="H0D1N";
printf ("size of string=%d\n",sizeof(a)) ;
printf ("strlen string=%u\n",strlen(a)) ;//strlen返回值为size.t定义在<string.h中,数据类型实际上是unsigned int ,所以用%u ,用%d也行
return 0;
}
输出结果:
size of string=6
strlen string=5
输出结果表明,strlen计算的是字符的个数,不包括数组后的’\0’,计算尺寸时才包括
- 拷贝字符串:strcpy&strncpy
字符串的拷贝不能使用赋值号,使用赋值号会有报错
#include <stdio.h>
#include <string.h>
int main()
{
char str1[]="Original string";
char str2[]="New string";
char str3[100];
strcpy(str1,str2);
strcpy(str3,"Copy successfully");
printf("str1:%s\n",str1);
printf("str2:%s\n",str2);
printf("str3:%s\n",str3);
return 0;
}
输出结果:
str1:New string
str2:New string
str3:Copy successfully
str2的内容复制到str1内后为何str1多出来的“tring”不被打印??
复制的过程将’\0’也复制了进去。编译器读到’\0’时让字符串结束了
注意!!!:使用该函数时要保证目标字符数组足以容纳零数组(即逗号左边的容量容得下右边的),**
strcpy(str2,str1);//错误的!!
但很奇怪,我这样写编译器还能正常输出。
- strncpy
#include <stdio.h>
#include <string.h>
int main()
{
char str1[]="To be or not to be";
char str2[40];
strncpy(str2,str1,5);//5是用于限制原字符串拷贝过去的长度,不包括结束符
str2[5]='\0';//由于结束符没有被拷贝,所以要手动添加!!!!!
printf("str2=%s\n",str2);
return 0;
}
输出结果
str2=To be
- 连接字符串:strcat&strncat
要求:目标数组(左边的)已经包含一个字符串,也可以是一个空字符串即“ ”,它会找到这个字符串的末尾,并把原字符串的一个拷贝给连接过去
#include <stdio.h>
#include <string.h>
int main()
{
char str1[]="H0";
char str2[]="D1N";
strcat(str1,str2);//str2也可以是一个字符串
printf("str1=%s",str1);
return 0;
}
输出:
str1=H0D1N
- strncat
strncat与strncpy相似,都要添加一个参数来限定连接字符串的个数,唯一不同的是,strncat会在连接后字符末尾自动添加’\0’
-
比较字符串:strcmp & strncmp
用此函数来比较两个字符串是否完全一致若完全一致,返回值是0,若存在差异,根据情况返回大于0或小于0的值。
原理:该函数从第一个字符开始,依次对比两个字符串每一个字符的ASC码,若第一个字符串字符的asc码小于对应的第二个字符串的字符,那么返回一个小于0的值,反之相反
例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[]="H0D1N";
char str2[]="H0D1N";
if(strcmp(str1,str2)==0)//也可以写!strcmp(str1,str2),strcmp使用后的值即为返回值
{
printf("两个字符串完全一致\n");
}
else
{
printf("两个字符串存在差异\n");
}
return 0;
}
- strncmp
相比strcmp增加了一个参数n,用于指定只对比前面的n个字符
二维数组
问题引出:存放单科的成绩用一个数组就可以,若要存放多个科目呢???
二维数组,我们通常也称它为矩阵,将二维数组写成行和列的形式方便我们理解,例:每一列都为一个数据种类,每一行都属于一个个体的数据
二维数组的定义:类型 数组名 [常量表达式] [常量表达式]
int a[6][6]//六行六列
char b[4][5]//四行五列
double c[3][4]//三行四列
在内存中的存放:
c语言内,c语言是线性的,二维数组的存放依然是线性的
例: 要定义一个四行五列的二维数组b 。首先,定义一个一维数组 b[0],b[1],b[2],b[3]为里面的元素,进而,每一个元素再存放一个一维数组,可以理解为数组的嵌套,它都是以线性的方式存放的,可以去查找图片配合理解。
二维数组的访问
- 数组名 【下标】【下标】(注意下标的取值范围,下标从0开始!!!)
a[0][0];//访问a数组中第一行第一列的元素
b[1][3];//访问数组b中第2行第4列的元素
二维数组的初始化
若没有初始化,数组内道德值为随机的
- 由于二维数组在内存中是线性存放的,因此可以将所有数据写在一个花括号内;
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
代码:
#include <stdio.h>
int main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",a[i][j]);
}
putchar('\n');
}
return 0;
}
输出:
1 2 3 4
5 6 7 8
9 10 11 12
- 为了更直白地表示元素的分布,可以用大括号将每一行的元素括起来
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12};
或者
int a[3][4]={{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};//会更直观
- 二维数组也可仅对部分元素赋初值:
int a[3][4]={{1},{3},{5}};
联系上一种情况,上句的意思是,将三行的每行第一个元素赋值为1,3,5,而其余没有被赋值的自动填充为0。
- 如果希望整个二维数组初始化为0,那么直接在大括号里写一个0即可
- C99同样增加了一种新特性:指定初始化的元素,这样就可以只对数组中的某些指定元素进行初始化赋值,而未被初始化的元素自动赋值为0
int a[3][4]={[0][0]=1,[1][3]=2,[2][3]=4};
- 二维数组的初始化也能偷懒,让编译器根据元素的数量计算数组的长度。但只有第一维的元素个数可以不写,其它维的个数必须写上
int a[][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12};
二维数组的转置
#include <stdio.h>
int main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int i,j;
for(j=0;j<4;i++)
{
for(i=0;j<3;j++)
{
printf("%d ",a[j][i]);//将ij调换即可完成
}
putchar('\n');
}
return 0;
}