文章目录
往期回顾
整型 int 4个字节
浮点型 float 4个字节
字符型 char 1个字节
system的使用:
函数原型:
包含在头文件stdlib.h中
int system(const char * command)
system(“pause”)可以实现冻结屏幕,便于观察程序的执行结果
system(“CLS”)可以实现清屏操作。
" "与’ '的区别:
用单引号引起来的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值。因此,对于采用ASCII字符集的编译器而言,'a’的含义是0141(八进制)或者97(十进制)严格一致。
用双引号引起来的字符串,代表的是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为零的字符’\0’初始化
一、一维数组
1.1 数组的定义
引言:
某班学生的学习成绩、一行文字、一个矩阵等数据的特点如下:
(1)具有相同的数据类型。
(2)使用过程中需要保留原始数据。
C语言为了方便操作这些数据,提供了一种构造数据类型——数组.所谓数组,是指一组具有相同数据类型的数据的有序集合。
1.1.1 数组定义表达式
一维数组的定义格式为:
类型说明符 数组名[常量表达式];
int a[10];
定义了一个整型数组,数组名为a,它有10个元素。
1.1.2 数组声明规则
(1)遵循标识符命名规则;
(2)在定义数组时,需要指定数组元素的个数,方括号中的常量表达式用来表示元素的个数,即数组的长度;
(3)常量表达式中可以包含常量和符号常量,但不能包含变量。也就是说,C语言不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值。
1.1.3 错误示范
int n; //这是声明变量n,并不是声明数组
scanf("%d,&n"); //在程序中临时输入数组的大小
int a[n];
float a[0]; //数组大小为0没有意义
int b(2)(3); //不能使用圆括号
int k=3,a[k]; //不能用变量说明数组大小
1.2 数组在内存中的存储
语句int mark[100];定义的一维数组 mark在内存中的存放情况如图所示
每个元素都是整型元素,占用4字节;
数组元素的引用方式是“数组名[下标]",所以访问数组 mark中的元素的方式是mark[0],mark[1]…, mark[99]。
注意:
没有元素mark[100],因为数组元素是从0开始编号的.
1.2.1 一维数组的初始化
- 在定义数组时对数组元素赋值
int a[10]={0,1,2,3,4,5,6,7,8,9};x
- 可以只给一部分元素赋值
int a[10]={0,1,2,3,4};
定义a数组有10个元素,但花括号内只提供5个初值,这表示只给前5个元素赋初值,后面5个元素的值为0
- 若要一个数组中全部元素的值为0,可写成
int a[10]={0,0,0,0,0,0,0,0,0,0};
或
int a[10]={0};
+在对全部数组元素赋初值,数据个数已经确定,因此可以不指定数组长度
int a[]={1,2,3,4,5};
1.2.2 举个例子
#include <stdio.h>
#include <stdlib.h>
//一维数组的传递,数组长度无法传递给子函数
//C语言的函数调用方式是值传递
void print(int b[],int len)
{
int i;
for(i=0;i<lenn;i++)
{
printf("%3d",b[i]);
}
b[4]=20; //子函数中修改数组元素
printf("\n");
}
//数组越界
//一维数组的传递
#define N 5
int main()
{
int j=10;
int a[5]={1,2,3,4,5};//定义数组时,数组长度必须固定
int i=3;
a[5]=20;//越界访问
a[6]=21;
a[7]=22;
print(a,5);
printf("a[4]=%d\n",a[4]); //a[4]发生改变
system("pause");
解释:
先定义的变量j的地址大于后定义的变量i的地址,所以先定义的变量放在高地址,后定义的变量放在低地址。其实每个函数开始执行时,系统会为其分配对应的函数栈空间,而变量j、变量a、变量i都在 main函数的栈空间中,由于后定义的变量在上面,因此这种效果称为栈向上增长。
在监视窗口中输入sizeof(a),可以看到数组a的大小为20字节,计算方法其实就是sizeof(int)*5:数组中有5个整型元素,每个元素的大小为4字节,所以共有20字节.访问元素的顺序是依次从a[0]到a[4], a[5]=20,a[6]=21均为访问越界.下图也显示了代码运行情况,从中看出,执行到第26行时,数组 a与变量j中间的8字节的保护空间已被赋值(微软公司的编译器在不同的变量间设置了保护空间),而执行到第27行时,变量j的值被修改了,这就是访问越界的危险性——未对变量j赋值,其值却发生了改变!
数组访问越界的错误提醒:
Run-Time Check Failure #2 - Stack around the variable ‘a’ was corrupted.
注意
数组在传递时,元素个数传递不过去,如果想知道数组里面有多少个元素,一开始传递的时候,再写一个int len;
二、字符数组
2.1 字符数组的定义及初始化
初始化字符数组时,一定要让字符数组的大小比看到的字符串的长度多
字符数组的定义方法:
char c[10];
字符数组的初始化可以采用以下方式:
- 对每个字符的单独赋值进行初始化
c[0]="1";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";
- 对整个数组进行初始化:
char c[10]={"I","a","m","h","a","p","p","y"}
但是,一般不用以上两种初始化方式,因为字符数组一般用来存取字符串,通常采用的初始化方式时cahr c[10]=“hello”。因为c语言规定字符串的结束标志为’\0’,而系统会对字符串常量自动加一个‘\0’.
为了保证处理的方法一致,一般会人为地在字符数组中添加‘\0’,所以字符数组存储的字符串长度必须比字符数组少一个字节。
举个例子
char c[10]最长存储9个字符,剩余的一个字符用来存储’\0’
字符数组初始化及传递
#include <stdio.h>
#include <stdlib.h>
void printf(char c[])
{
int i=0;
while(c[i])
{
printf("%c",c[i]);
i++;
}
printf("\n");
}
//字符数组存储字符串,必须存储结束符'\0'
//scanf读取字符串时使用%s
int main()
{
char c[5]={"h","e","l","l","0"};
char d[5]="how";
printf("%s---%s\n",c,d);//会发现打很多“烫”字
scanf("%s%s",c,d);
printf("%s---%s\n",c,d);
print(c);
system("pause");
return 0;
}
输出结果如下:
为什么对数组赋值“hello”却打印出很多“烫”字?
因为printf通过%s打印字符串时,原理是依次输出每个字符,当读到结束符’\0’时,结束打印;
scanf通过%s读取字符串时,对c和d分别输入“are”和“you”(中间记得加空格),scanf在使用%s读取字符串时,会忽略空格和回车。
字符数组的数组名里村的就是字符数组的起始地址
2.2 gets函数与puts函数
2.2.1 gets函数
引言:
gets函数类似于scanf函数,用于读取标准输入。
通过上面我们已经知道scanf函数在读取字符串时遇到空格就认为读取结束,这样没办法把一行带空格的字符串存入到一个数组中,所以当输入字符串存在空格时,我们需要使用gets函数进行读取。
gets函数格式如下:
char *gets(char *str);
原理:gets函数从STDIN(标准输入)读取字符并把他们加载到str(字符串)中,直到遇到换行符(\n)或达到EOF。
注意:gets遇到\n后,不会存储\n,而是将其翻译为空字符’\0’
2.2.2 puts函数
引言:
puts函数类似于printf函数,用于输出标准输出
puts输出的就是字符串,printf可以支持多种格式输出
puts函数格式如下:
int puts(char *str);
2.3 str系列字符串操作函数
str 系列字符串操作函数主要包括strlen、strcpy、strcmp、strcat等;
(1)strlen函数用于统计字符串长度,不考虑后面的\0;
(2)strcpy函数用于将某个字符串复制到字符数组中
(3)strcmp函数用于比较两个字符串的大小,相等返回为0,若前面字符串大于后面的字符串,则返回为1,反之,为-1;比较的是对应字符的ASCII码值
(4)strcat函数用于将两个字符串连接到一起;
#include <string.h>
size_t strlen(char *str);
char *strcpy(char *to,const char *from);
int strcmp(const char *str1,const char*str2);
char *strcat(char *str1,const char *str2);
对于传参类型char*,直接放入数组的数组名即可
str系列字符串操作函数的使用!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mystrlen(char [])
{
int i=0;
while(c[i++]);
return i-1;
}
//strlen统计字符串长度
int main()
{
int len;//用于存储字符串长度
char c[20];
char d[100]="world";
while(gets(c)!=NULL)
{
puts(c);
len=strlen(c);
printf("len=%d\n",len);
len=mystrlen(c);
printf("mystrlen len=%d\n",len);
strcat(c,d);
strcpy(d,c);//c中的字符串复制给d
puys(d);
printf("c?d %d\n",strcmp(c,d));
puts(c);
}
system("pause");
return 0;
}
- 通过gets函数循环读取字符串的目的是,方便不断地输入不同的字符串并查看程序的执行效果,并在修改程序中的某部分后能够以多种输入进行测试,如果要结束循环,按ctrl+z。
- strcpy函数用来将字符串中的字符逐个地赋值给目标字符数组。例如我们将c复制给d,就是将c中地每个字符依次赋值给d,也会将结束符赋值给d。
注意,目标数组一定要大于字符串大小,即sizeof(d)>strlen©,否则会造成访问越界。 - strcmp函数用来比较两个字符串的大小,由于字符数组c中的字符串与d相等,所以这里的返回值为0。
如果c中的字符串大于d,那么返回值为1;如果c中的字符串小于d,那么返回值为-1,如何比较两个字符串的大小呢?
从头开始,比较相同位置字符的ASCII码值,若发现不相等则直接返回,否则接着往后比较。
举个例子
strcmp(“hello”,“how”)的返回值是-1,即hello<how。因为第一个字符h相等,接着比较第二个位置的字符,e的ASCII码值小于o的,然后返回-1。
strcat函数用来将一个字符串接到另一个字符串的末尾。
举个例子
字符数组c中存储的是hello,我们将d中的world与c拼接,最终结果是helloworld。
注意目标数组必须大于拼接后的字符串大小,即sizeof©>strlen(“helloworld”).