C 语言基础:第 08天笔记
内容提要
- 数组
- 排序算法:冒泡排序
- 二维数组
- 字符数组
数组
冒泡排序
-
排序思想(向前冒泡):
- 一次排好一个数,针对n个数,最差情况需要n - 1次就可以排好
- 每次排序假定第一个元素是最大或者最小的,相邻的两个元素比较,遇到较大或者较小的元素交换,访问完数组的最后一个元素,就排好了一个数。
- 在余下的数中,再次应用第2步的操作,直到剩下1个数。
-
推理:
例如:将
5,4,3,2,1
冒泡排序为1,2,3,4,5
排序演示:
- 第1轮:5,4,3,2,1 → 4,3,2,1,
5
比较4次 = 数组长度5 - 轮数1 - 第2轮: 4,3,2,1,
5
→ 3,2,1,4,5
比较3次 = 数组长度5 - 轮数2 - 第3轮:3,2,1,
4,5
→ 2,1,3,4,5
比较2次 = 数组长度5 - 轮数3 - 第4轮:2,1,
3,4,5
→ 1,2,3,4,5
比较1次 = 数组长度5 - 轮数4
- 第1轮:5,4,3,2,1 → 4,3,2,1,
-
总结:
-
案例设计到5个数的排序,排序了4轮,得到:轮数 = 元素个数(数组打小) - 1,我们可以通过一个外层for循环实现轮数的遍历。
-
案例涉及的每一轮中数列的排序次数,得到:次数 = 元素个数 - 轮数[-1],我们可以通过一个内层for循环实现每一轮次数的遍历。
-
每一次比较过程中,两个数设计到位置交换,比如a = 3,b = 4,交换ab的数据变为a = 4,b = 3,应该如何实现:
-
引入一个临时变量temp,将a的值赋值给temp,int temp = a;
-
将b的值赋值给a,a = b;
-
将temp的值赋值给b,b = temp;
-
-
-
代码:
c#include <stdio.h> int main() { //创建一个数组,用来存放排序用的数列 int arr[10]; //定义循环变量和临时变量 int i,j,temp; printf("请输入10个整数:\n"); //计算数组的大小 int len = sizeof(arr) / sizeof(arr[0]); 等价于 sizeof(arr) / sizeof(int); //通过循环给数组元素赋值 for(i = 0; i < len; i++) scanf("%d",&arr[i]); //[]优先级高于&,等价于&(arr[i]) printf("\n"); //冒泡排序 //外层循环:实现排序轮数的遍历,轮数 = 数组大小 - 1 for(i = 0; i < len -1, i++) { int flag = 0; //设置一个flag,用来判断是否已经有序 //内存循环:实现每一轮的比较次数,比较次数 = 数组大小 - 轮数 - 1 for(j = 0; j < len -i -1; j++) { //相邻的两个数比较后交换位置 if(arr[j] > arr[j+1]) //此时,实现升序排序,从小到大 { temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; flag = 1; } } if(flag == 0) break; //如果进行了一轮排序后flag还是等于0,则说明已经有序 } printf("冒泡排序后从小到大为:\n"); for(i = o; i < len; i++) printf("%4d", arr[i]); pritnf("\n"); return 0; }
-
衍生
冒泡排序 → 鸡尾酒排序(摇坠排序) → 摇床排序...
二维数组
定义
二维数组本质上是一个行列式组合,也就是说二位数组由行和列两部分组成。属于多维数组。二维数组数据通过行和列解读(先行后列)。
二维数组可以被视为一个特殊的一维数组,也就是说当一个数组的元素是一维数组的时候,这个数组就是二维数组。(数组的元素的类型可以是数组类型)
语法
c
数据类型 数组名[行数][列数];
行数:外层数组的数组容量
列数:内层的数组容量
说明
- 二维数组在初始化的时候,可以省略行数,系统会通过初始化后的数据自动推断行数。
- 二维数组和一位数组一样,也可以部分初始化,未初始化的元素使用
0
(整形和浮点型)、\0
(字符型,\0
对应的ASCII是0),NULL
(指数相关) - 二维数组的初始化的时候,不能省略列数,否则编译报错。
举例
c
int arr[3][3] = {{11,12,13},{21,22,23},{31,32,33}}; //正确,等价于下面写法
int arr[][3] = {{11,12,13},{21,22,23},{31,32,33}}; //正确,二维数组初始化的时候可以省略行数,推荐写法
int arr[3][3] = {{11,12},{21,22,23},{31}}; //正确,缺失部分情况根据情况补0、\0、NULL、补什么由数据类型决定
int arr[3][3] = {{11,12,0},{21,22,23},{31,0,0}}; //正确,等价于上面写法
int arr[3][3] = {0}; //正确,所有位置使用0补齐
int arr[3][3] = {}; //正确,所有位置用0补齐
int arr[3][3] = {11}; //正确,除了第0行第0列使用11以外,其他位置用0补齐
int arr[3][3] = {{11,12,13},{21,22,23},{31,32,33}}; //错误,编译报错,不能省略列数
int arr[3][] = {{11,12,13},{21,22,23},{31,32,33}}; //错误,编译报错,不能省略列数
注意:在C语言中,二维数组在计算机的存储顺序是按行进行的,即第一维(行)下标变化慢,第二维的(列)下标变化快
内存存储

应用场景
主要是应对行列有要求的情况。比如说我们先存储所有在班学生的成绩
还有就是字符数组的应用,比如用数组存储学生的姓名。
double scores[28] = {..};
一维数组初始化
double scores[5][40] = {``{..}..}
二维数组初始化
double scores[6][4][40] = {``{``{..}..}..}
三维数组初始化
特殊写法
- 下标可以是整型表达式。如:
a[2-1][2*2-1] → a[1][3]
- 下标可以已经有值的变量或者数组元素,如:
a[2*x-1][b[3][1]]
- 数组元素可以出现在表达式中,如:
b[1][2] = a[2][3]/2
注意:使用数组元素的下标应在已定义数组的大小范围内;应注意区别定义数组大小和引用数组元素的区别
初始化
-
分行给二位数组赋初值
cint arr[3][4] = {{11,12,13,14},{21,22,23,24},{31,32,33,34}};
-
可将所有数据写在一个花括号内,按照顺序对元素赋值
cint arr[3][4] = {11,12,13,14,21,22,23,24,31,32,33,34};
-
可对部分元素赋初值,其余未赋值部分自动填充
数值类型默认值-0 | 字符型默认值-\0 | 指针类型-NULL
cint arr[3][4] = {{11},{21,22},{31}};
-
若对全部元素赋初值,自定义数组时可以省略第1维数组的长度(行数),第2维数组的长度(列数) 必须指明。
cint a[][4] = {11,12,13,14,21,22,23,24,31,32,33,34};
-
在分行赋初值时,也可以省略第1维的长度(行数)。
cint arr[][4] = {{11,12,13},{0},{0,10}};
案例
案例1
-
需求:二维数组的遍历
-
分析:
-
二维数组的遍历需要使用到嵌套for循环,外层训话遍历行,内层循环遍历列
-
取值:
c数组名[行号][列号];
-
赋值
c数组名 [行号][列号] = 值;
-
-
代码
c#include <stdio.h> int main() { //创建一个二维数组 int arr[][3] = {{11},{21,22},{31,32,33}}; //11,0,0,21,22,0,31,32,33 //获取行容量和列容量 int row = sizeof(arr) / sizeof(arr[0]); int col = sizeof(arr[0]) / sizeof(arr[0][0]); //遍历数组 //外层循环:遍历行 for (int i = 0; i < row; i++) { for (int j = o; j < col, j++) { printf("%-3d",arr[i][j]); } } printf("\n"); return 0; }
-
运行结果
案例2
-
需求:矩阵的转置
-
分析:
- 所谓的转置,就是原本的列变行,行变列
-
代码:
c#include <stdio.h> #define ROW 2 #define COL 3 int main() { //定义循环变量i,j int i, j; //准备2个数组用来存储转置前后的数据 int arr_before[ROW][COL] = {11,12,13,21,22,23}; int arr_after[COL][ROW] = {0}; //计算数组的大小 int arr_before_row = sizeof(arr_before) / sizeof(arr_before[0]); int arr_before_col = sizeof(arr_before[0]) / sizeof(arr_before[0][0]); int arr_after_row = sizeof(arr_after) / sizeof(arr_after[0]); int arr_after_col = sizeof(arr_after[0]) / sizeof(arr_after[0][0]); //通过嵌套for循环实现转置 printf("转置前:\n"); for (i = 0; i < arr_before_row; i++) { for(j = 0; j < arr_before_col; j++) { //打印输出装置前的数据 printf("%-4d",arr_befire[i][j]); //转置。列变行,行变列 arr_after[j][i] = arr_before[i][j]; } ptintf("\n"); } ptintf("\n"); printf("转置后:\n"); for (i = 0; i < arr_after_row; i++) { for (j = 0; j < arr_after_col; j++) printf("%-4d",arr_after[i][j]); printf("\n"); } printf("\n"); return 0; }
-
运行结果
课堂练习
- 需求:求一个3行3列的矩阵对角线上的元素之和。
字符数组
在C语言中,支持常量字符串,不支持变量字符串,如果想要实现类似的变量字符串,C语言提供了两种实现方式:
-
字符数组
cchar name[] = "哪吒";
-
字符指针
cchar *name = "哪吒";
概念
元素类型为char(字符型)的数组叫做字符数组。字符数组往往是用来存储字符串数据的。需要注意的,我们C语言中的字符是字节字符(1字符 = 1字节,C语言中没有字节这个表示法,我们一般使用char表示字节,1char = 8bit)。
硬件中存放数据以bir(位)为单位,系统对于内存的操作以char(字节)为单位。系统为内存以1个字节为单位进行编号。
实验:
c
char a = 'A'; //正确
char b = '1'; //正确
char c = '65'; //正确,这里的65是ASCII码,char的值有两种表现形式,一种是字符,一种是字符对应的ASCII码
char d = "A"; //错误,用双引号包裹的内容是常量字符串
char a = '王'; //错误,ASCII中不包括中文字符,中文字符使用的是如GBK、UTF-8等编码,实际上都超过了1个字节
语法
一维数组:
c
char 数组名[数组容量];
二维数组:
c
char 数组名[行容量][列容量]
字符数组的语法就是我们之前所学的一维数组和二位数组的语法,只不过数据类型是char而已。
注意:
如果我们char数组初始化的时候,没有完全初始化值的时候,使用\0
进行填充。大家要注意,这里的\0
只是起到一个站位或标识的作用,我们是无法通过printf等打印输出到控制台的(不支持输出)。
比如:
c
char c[8] = {'H','E','L','L','O'}; //部分初始化,未初始化部分补'\0',等价于下面写法
char c[8] = {'H','E','L','L','O','\0','\0','\0'};
案例1
-
需求:输出一个字符序列(I LOVE YOU)
-
代码
c#include <> int main() { //创建一个数组,用来存储 I LOVE YOU,ASCII中对应的空格为' ',其对应的ASCII码为32 char arr[] = {'I',' ','L','O','V','E',32,'Y','O','U'}; //计算数组的大小 int len = sizeof(arr) / sizeof(arr[0]); //使用for循环遍历 for (int i = 0; i < len; i++) printf("%c",arr[i]); printf("\n"); return 0; }
案例2
-
需求:输出一个用字符
*
组成的空菱形图案 -
代码:
cint main() { //创建一个二维数组,存放空菱形 char arr[5][5] = { {' ',' ','*',' ',' '}, {' ','*',' ','*',' '}, {'*',' ',' ',' ','*'}, {' ','*',' ','*',' '}, {' ',' ','*',' ',' '}, }; //计算行数和列数 int row = sizeof(arr) / sizeof(arr[0]); int col = sizeof(arr[0]) / sizeof(arr[0][0]); //遍历数组 for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) printf("%c", arr[i][j]); printf("\n"); } printf("\n"); return 0; }
注意
-
如果定义时,不初始化,元素的值不确定(针对局部定义的数组)
cchar arr1[2]; //如果这个数组是定义在函数中的,此时元素的值是随机的 char arr2[5] = {'a','b','c'}; //此时属于不完全初始化,未初始化完的元素使用'\0'填充
-
如果提供的字符个数大于数组长度,按照语法错误处理(会报警告,但是能编译通过);如果字符个数小于数组长度,后面的元素自动补
\0
cchar arr1[2] = {'h','e','e'}; //编译通过,但会报警,不建议写 char arr2[3] = {'a'}; //正确的,未初始化的元素使用'\0'填充
-
如果提供的字符个数和数组长度相同,可以省略数组长度,系统会自动确定元素个数,适合字符较多时。
cchar arr1[] = {'b','u'}; //正确,更具初始化元素,由系统自动计算元素个数
字符串结束标志
说明
-
C语言规定,字符串以字符
\0
作为结束标志 -
编译系统对字符串常量自动加一个
\0
作为结束的标志。比如char *name = "tom",实际上存储为{'t','o','m','\0'} -
程序中往往通过判断
\0
来检测字符串是否结束。举例:while(arr[i] != '\0'){...} -
\0
的ASCII码是0,不是一个可显示可输出的字符,是"空操作符",它什么都不做,不会增加有效字符,仅仅用作一个工程判别的标志或者在字符组中占位。cchar a[] = {'h','i'}; //hi char a[] = {'h','i','\0'}; //hi char c[] = "hello"; //实际存储:hello\0 字符常量,在内存中,默认加了一个\0字符用作结尾标志
字符数组的多样表示
我们的char数组可以以数组的形式一个一个输出每个字符;也可以以字符串的形式整体输出。
-
演示
cint main() { //字符串的第1种表示: char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'}; //字符串的第2种表示: char s2[] = {"hello world"}; //""包裹的字符串一般默认有一个\0,所以不需要手动加 //字符串的第3种表示: char s3[] = "hello world"; //字符串输出第1种方式: int len = sizeof(s3) /sizeof (s3[0]); for(int i = 0; i < len; i++) { //过滤\0 if (s1[i] == '\0' || s2[i] == '\0' || s3[i] == '\0') continue; printf("%c,%c,%c\n",s1[i],s2[i],s3[i]); } printf("\n"); //字符串输出的第二种方式 printf("%s,%s,%s\n",s1,s2,s3); printf("\n"); return 0; }
注意
-
字符串的长度与字符数组的长度不一定相同。
cchar *name = "hello"; // 数组长度:6,字符串长度:5
-
利用字符串常量可以对字符数组进行初始化,但不能用字符串常量对字符数组赋值。
c//正确演示:利用字符串常量给字符数组初始化 char arr1[] = "hello"; //错误演示:利用字符串常量给字符数组赋值 char arr[6] arr2 = "hello"; //可以理解为,数组是一个常量
字符串的基础操作
在用格式化说明符%s进行和输入输出时,其输入输出项均为数组名。但在输入时,相邻两个字符串之间要用空格分隔,系统将自动在字符串后加\0
。在输出是,要到结束符\0
作为输出结束标志。
对于字符串的操作,我们需要用到一些系统提供的API函数。
字符串输入
scanf
语法:
c
scanf ("%s",数组名);
注意:数组名对应的数组只能是char类型,从控制台输入字符串之后,默认为追加\0
案例:
c
int main()
{
//创建一个字符数组,用来存储姓名
char name[20]; //初始化的时候,数组容量可以省略,char name[] = {..},如果只是声明,数组容量不能省略
printf("请输入您的名字:");
scanf("%s", name); //数组本身没有空间,它的内存空间其实就是其元素空间
printf("您的姓名是:%s\n",name);
return 0;
}
注意:采用scanf进行字符串输入,要求字符串中不能有空格,否则字符穿遇到空格就会结束。
fgets
语法:
c
fgets(数组名,数组容量,stdin);
功能:
从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一 般用12位16进制数表示)
说明:
采用fgets进行字符串输入,可获取所有输入的字符串,包含\n,在实际的字符串处理时,我们 可能需要手动处理\n
案例:
c
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个字符数组,用来存储姓名
char name[20]; // 初始化的时候,数组容量可以省略,char name[] = {..},如果只是声明,数组容量不能省略
// 计算数组容量
int len = sizeof(name) / sizeof(name[0]);
printf("请输入您的名字:\n");
// scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向第一个元素的首地址
fgets(name,len,stdin);
printf("您的姓名是:%s\n",name);
return 0;
}
注意:
①如果输入的字符串不包括空格或换行,可以使用scanf或者fgets
②如果输入的字符串包括空格和换行只能使用fgets
gets危险的【 C11 移出】
语法:
c
gets(数组名);
功能:
从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一 般用12位16进制数表示)
说明:
采用gets进行字符串输入,可获取所有输入的字符串,包含\n
,在实际的字符串处理时,我 们可能需要处理\n
案例:
c
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个字符数组,用来存储姓名
char name[20];
// 计算数组的大小
int len = sizeof(name) / sizeof(name[0]);
printf("请输入您的名字:\n");
gets(name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向的就是首地址
printf("您的名字是%s\n",name);
return 0;
}
字符串输出
printf
语法:
c
printf("%s",数组名);
案例:
c
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个字符数组,用来存储姓名
char name[20];
printf("请输入您的名字:\n");
scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向的就是
首地址
printf("您的姓名是%s\n",name);
return 0;
}
fputs
语法:
c
fputs(数组名,shdout);
功能:
输出一个字符串
说明:
字符串可以包含转义字符(以\
开头的字符)
案例:
c
#include <stdio.h>
int main(int argc,char *argv[])
{
char arr[] = "hi lucy\trun!\n";
// 第1种输出
printf("%s",arr);
// 第2种输出
fputs(arr,stdout);
return 0;
}
puts 危险的【C11移出】
语法:
c
puts(数组名称)
功能:
输出一个字符串
说明:
字符串可以包含转义字符
案例:
c
#include <stdio.h>
int main(int argc,char *argv[])
{
// 创建一个数组,用来存放人的名字
char name[20];
printf("请输入您的名字:\n");
// gets、fgets和scanf只能多选一
gets(name);
// 输出
puts(name);// 标准的输出
return 0;
}
字符串转数值【扩展】
-
strtol
clong strtol (const char *str, char **endptr, int base);
将字符串转换为长整型数。
参数说明:
str :
指向要转换的字符串的指针。endptr
:一个指向字符指针的指针。如果提供了这个参数,并且转换成功,*endptr
将被 设置为指向第一个未转换字符的指针。如果endptr
是NULL
,则不使用它。base
:用于指定转换的基数。它可以是 2 到 36 之间的值,或者是特殊值 0。如果base
是 0,则函数会根据字符串的前缀(如 "0x" 或 "0X" 表示十六进制,"0" 表示八进制,否则默 认为十进制)来自动确定基数
-
strtoul
cunsigned long strtoul(const char *str, char **endptr, int base);
将字符串转换为无符号长整型数。
-
strod
cdouble strtod(const char *str, char **endptr);
-
atoi
cint atoi(const char *str)
将字符串转换为长整型数(不推荐使用,建议使用
strtol
)。 -
atof
cdouble atof(const char *str);
将字符串转换为双精度浮点数(不推荐使用,建议使用
strtod
)。
案例:
c
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
printf("%lo,%ld,%lx\n",strtol("12",NULL,8),strtol("12",NULL,10),strtol("12",NULL,16));
printf("%lo,%ld,%lx\n",strtol("012",NULL,0),strtol("12",NULL,10),strtol("0x12",NULL,0));
int a = 10;
printf("%p,%lx\n",&a,&a);
return 0;
}
main()
{
int a=2,b=-1,c=2;
if(a<b)
if(b<0) c=0;
else c+=1;
printf("%d\n",c);
}
关于单字符的输入:
- scanf("%c",...)
- getchar();
关于单字符的输出:
- printf("%c",...);
- putchar();
字符串相关函数
字符串拼接
语法:
c
strcat(字符串1,需要拼接的字符串2);
解释:
①这里的字符串,可以是字符串常量,也可以是字符数组或者字符指针。
②这里需要将字符串2拼接到字符串1中,所以需要字符串1有足够大的空间去容纳字符串2.
引入
c
#include <string.h>
案例:
-
需求:将两个字符串拼接为一个字符串
-
分析:
-
代码:
c#include <stido.h> #include <string.h> int main() { //创建一个数组,用来接收控制台输入的字符常量,字符串1 char namr[20]; printf(""请输入您的名字:\n); //通过键盘录入字符串 fegets(name, sizeof(name) / sizeof(name[0], stdin); //输出拼接 fputs(stract(name, "小帅"), stdout); printf("拼接后字符串所占字节数:%d\n", sizeof(trcat(name,"小帅"))); printf("\n"); return 0; }
注意:
① 字符串1
必须是字符数组,长度必须足够大,以便于能够容纳被链接的字符串。
② 连接后系统将自动取消字符串1
后面的结束符\0
③ 字符串2
可以是字符数组名,也可以是指针,也可以是字符串常量,如:strcat(s1,"def"); strcat(s1,s2);
字符串拷贝
语法:
c
strcpy(数组名,字符串);
解释:简单来说,类似于将一个字符串赋值给一个字符数组。这个函数一般用来做赋值处理。
引入:
c
#include <string.h>
**说明:**这个函数适合给字符串赋值
c
char str[20] = "张三"; //正确,字符数组初始化,字符串初始化
char str[20] = "张三"; str = "李四"; //错误,不能对字符数组进行赋值
char str[20] = "张三"; strcpy(str, "李四"); //正确,借助strcpy完成类似赋值的操作
**注意:**strcat和strcopy的区别:
- strcat: 张三+李四 → 张三李四 (追加)
- strcpy:张三+李四 → 李四 (覆盖)
案例:
c
#include <stdio.h>
#include <string.h>
int main()
{
char name[20];
printf("请输入您的姓名:\n");
fgets(name, sizeof(name) / sizeof(name[0], stdin)); // 键盘 → 输入缓冲区 → char name[]
printf("覆盖前:%s\n", name);
//重新赋值
strcpy(name, "谢谢惠顾");
printf("覆盖后:%s\n", name);
return 0;
}
字符串比较
语法:
c
strcmp(字符串1,字符串2);
注意:这里的字符串可以是字符常量、字符数组、字符指针。
引入:
c
#include <string.h>
**功能:**如果是英文,比较两个字符串对应位置字符ASCII的大小
返回值:
- 如果字符串1等于字符串2,返回0
- 如果字符串1大于字符串2,返回正数(>0)
- 如果字符串1小于字符串2,返回负数(<0)
说明:
①执行这个函数是,自左向右诸葛比较对应字符的ASCII的值,知道发现了不同字符或字符串结束符\0为止
②对字符串不能用数值型比较符。比如:"abc"
== "abc"
,这种比较是错误的。
③字符串1与字符串2可以是字符数组、字符指针、字符串常量。
案例:
-
需求:通过控制台输入用户名和密码,并进行校验
-
代码:
c#include <stdio.h> #include <string.h> int main() { //用户登录案例 //创建两个变量,用来接受控制台输入的用户名和密码 char username[20], password[8]; printf("-----------用户登录-----------"); printf("请输入您的用户名:\n"); scanf("%s", username); printf("请输入您的密码:\n"); scanf("%s", password); //校验 if(strcmp(username,"admin") && strcmp(password, "123456")) //问题: printf("登录成功!\n"); else printf("用户名或者密码错误!\n"); return 0; }
-
运行结果
字符串长度
- 语法:
c
strlen(字符串);
- 引用:
c
#include <string.h>
注意:返回字符串种包含的实际个数。遇到\0结束,不包含\0
案例:
-
需求:字符串长度案例
-
代码:
c
#include <stdio.h>
#include <string.h>
int main()
{
//测试数据1
char s1[] = {'h','i','\0','h','i','\0'};
printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s1)/sizeof(s1[0]),strlen(s1)); // 6 2
//测试数据2
char s2[] = "hi\0hi\0";
printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s2)/sizeof(s2[0]),strlen(s2));// 7 2
//测试数据3
char s3[] = {'hi','e','l','l','0'};
printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s3)/sizeof(s3[0]),strlen(3)); // 5 5
//测试数据4
char s4[] = "hello";
printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s4)/sizeof(s4[0]),strlen(4));//4 5
return 0;
}
-
运行结果:
案例
-
需求:输入一行字符,统计其中有多少个单词,单词之间用空格隔开。举例:I LOVE YOU
-
分析:采用通过空格统计单词的方法。具体是:
① 用连续若干个空格算一个、一行开头的空格不计的方法决定单词数目;
② 从第一个字符开始逐个检查字符串中的每一个字符。若查到某一字符非空格,而其前面的字 符是空格,则表示新单词开始,让计数变量num++。否则,当前字符非空格,前面字符也非空 格,则非新单词,num不变;
③ 用变量word=0或1来表示前面字符是空格或不是空格。则:
-
代码:
c#include <stdio.h> #include <ctype.h> int main() { //创建一个字符数组,用来接收控制台输入的字符串 char string[100]; //创建两个变量,word = 0;用来标记遍历出来的字符是否是空格,01空格,1-非空格;num = 0:记录单词的个数 int num = 0, word = 0; //用来接收遍历出来的字符 char c; //通过控制台输入字符串(包含空格) fgets(string, sizeof(string) / sizeof(string[0])), stdin); //遍历字符串 for(int i = 0;(c = string[i]) != '\0'; i++) { //如果取出来的字符是空格,就设置word = 0 if(isspace(c)) { //如果是空格,标记word = 0 word = 0; } else { //如果是非空格,标记 word = 1 //如果上一个字符是否是空格,如果是,就需要统计单词 if(!word) //word == 0 { //更改word = 1 word = 1; //统计单词个数 num++; } word = 1; } } printf("%s\n中有%d个单词"); return 0; }
案例
有三个字符串,要求找出其中最大者。
分析:设计一个二维字符数组str3,即3行20列。
① 可把str[0]、str[1]、str[2]看作3个一维字符数组,各有20个元素;
② 用gets函数分别输入3个字符串到str[0]、str[1]、str[2]中 ;
③ 用字符串函数对str[0]、str[1]、str[2]进行比较,得到最大者。
c
#include <stdio.h>
#include <string.h>
void main ( )
{
char max[20];
char str[3][20];// 输入3个字符串 {"abc","bbc","ccc"}
int i;
// 完成初始化
for (i=0;i<3;i++)
gets(str[i]); /*输入3个字符串*/
// fgets(str[i],20,stdin)
if (strcmp(str[0],str[1])>0) /*比较,若串0>串1*/
strcpy(max,str[0]); /*把串0存入string*/
else
strcpy(max,str[1]); /*否则,把串1存入string*/
if (strcmp(str[2],max)>0) /*再比较,若串2>string*/
strcpy(max,str[2]); /*把串2存入string,否则string不变*/
printf("\nthe largest string is:\n%s\n",max); /*输出string*/
}