嵌入式Linux学习路线分享---C语言(4)

目录

一、一维数组

1.数组概念

2. 一维数组的概念

3. 定义一维数组

4. 一维数组的性质

5. 一维数组的初始化

二、二维数组

1. 概念

2. 定义二维数组的格式

3 .二维数组的初始化

三、字符数组和字符串

四、字符串处理函数

1.strlen()

2.strcpy

3. strcat

4.strcmp

五、冒泡排序法

1.基本思想:

2.详细步骤:(以升序为例 从小到大)

 3.代码实现:


一、一维数组

1.数组概念

数组使用来管理一组相同数据类型的数据的。

数组是一个构造类型。

数组中的每个相同的数据类型的数据称为数组的元素、或者叫数组的成员。

数组的成员在内存上一定是连续的,不管是几维数组,都是连续的。

2. 一维数组的概念

所谓的一维数组,就是下标只有一个的数组,他在内存上是连续的。

3. 定义一维数组

存储类型 数据类型 数组名[下标];

存储类型:先不用管,后面讲,不写的默认就是 auto

数据类型:既可以是基本类型,也可以是构造类型(数组除外)

数组名:是一个标识符,要符合标识符命名规范

下标:在定义数组时,下标只能是一个常量,用来表示数组的长度(元素的个数)

在定义数组之后,使用下标时,既可以是常量、也可以是变量,

也可以是表达式,表示取数组的第几个元素

例:

int s[10]; //定义了一个数组,数组名为s,数组中最多能存储10个元素

每个元素都是一个 int 类型。

4. 一维数组的性质

#include <stdio.h>

int main(int argc, const char *argv[])
{
	//定义了一个名为s 长度为5 每个元素都是int 的数组
	int s[5];

	//访问数组成员的方式
	//数组名[下标] 方式来访问
	//下标是 从 0 开始的,长度为5的数组最大的下标应该是4
	//取到s某个成员后 int 类型的变量怎么用  这个成员就怎么用 
	s[0] = 10;
	s[1] = 20;
	s[2] = 30;
	s[3] = 40;
	s[4] = 50;
	printf("s[0] = %d\n", s[0]);//10
	printf("s[1] = %d\n", s[1]);//20
	printf("s[2] = %d\n", s[2]);//30
	printf("s[3] = %d\n", s[3]);//40
	printf("s[4] = %d\n", s[4]);//50

	//数组在定义之后就不能整体赋值了
	//只能一位一位的赋值
	//s = 10,20,30,40,50; //错误的


	//一维数组的成员在内存上是连续的
	// &  取变量的地址
	// %p 可以输出地址
	// 下面的地址输出的是连续的
	printf("&s[0] = %p\n", &s[0]);
	printf("&s[1] = %p\n", &s[1]);
	printf("&s[2] = %p\n", &s[2]);
	printf("&s[3] = %p\n", &s[3]);
	printf("&s[4] = %p\n", &s[4]);

	//一维的大小 = sizeof(成员类型) * 成员的个数
	printf("sizeof(s[0]) = %ld\n", sizeof(s[0]));//4
	printf("sizeof(s) = %ld\n", sizeof(s));//20

	printf("--------------------------------\n");
    //使用循环给数组成员赋值
	int i = 0;
	for(i = 0; i < 5; i++){
		s[i] = (i+1)*100;
	}

	//一维数组的遍历
	for(i = 0; i < 5; i++){
		printf("s[%d] = %d\n", i, s[i]);
	}

	printf("--------------------------------\n");

	for(i = 0; i < sizeof(s)/sizeof(s[0]); i++){
		printf("s[%d] = %d\n", i, s[i]);
	}

	return 0;
}

5. 一维数组的初始化

#include <stdio.h>

int main(int argc, const char *argv[])
{
	//方式1:完全初始化
	//short hqyj[5] = {10, 20, 30, 40, 50};//10 20 30 40 50
	
	//方式2:不完全初始化
	//按下标是小到大初始化,没有初始化的位,会初始化成 0
	//short hqyj[5] = {10, 20};//10 20 0 0 0
	
	//方式3:所有成员都初始化成 0
	//----这种方式在开发中比较常用
	//short hqyj[5] = {0};// 0 0 0 0 0

	//方式4:省略下标的方式初始化
	//这种方式 编译器会根据后面元素的个数 自动给数组分配空间
	//short hqyj[] = {10, 20, 30, 40, 50, 60};
	//printf("%ld\n",sizeof(hqyj));//12 = sizeof(short) * 6

	//数组如果没有初始化,里面存的是随机值
	//short hqyj[5];

	//数组一旦定义完成了 就不能整体赋值了
	//short hqyj[5];
	//hqyj[4] = {10, 20, 30, 40};//错误的用法
	
	//!!!!!!!!!!!!!!!
	//数组名是一个地址常量,里面存的就是数组的首地址,也就是首元素的地址
	short hqyj[5];
	printf("&hqyj[0] = %p    hqyj = %p\n", &hqyj[0], hqyj);
	//既然是常量 就不能被赋值 也不能进行 hqyj++ 操作
	//hqyj++;//错误的
	short hqyj2[5] = {1, 2, 3, 4, 5};
	//hqyj = hqyj2;//错误的

	int i = 0;
	for(i = 0; i < 5; i++){
		printf("%d  ", hqyj[i]);
	}
	printf("\n");

	//数组越界访问的问题,编译器不会做检查,需要程序员自己检查
	//所以使用数组时,一定要注意,下标不要越界
	//一旦越界了,出现的错误是不可预知的
	printf("------------------------\n");
	hqyj[5] = 100;//已经使用了非法内存,错误已经不可预知了,千万不要这样使用
	printf("hqyj[5] = %d\n", hqyj[5]);

	return 0;
}

练习:

1.定义整型数组,长度为10,在终端给数组赋值

赋值后,找出数组最大的元素,及最大元素的下标,并输出。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int s[10] = {0};
	int i = 0;
	//循环给数组成员赋值
	for(i = 0; i < 10; i++){
		scanf("%d", &s[i]);
	}

#if 0
	//如果找最大值,注意 要使用这一组数据中的某一个来开始
	int max = s[0];
	for(i = 1; i < 10; i++){
		if(s[i] > max){
			max = s[i];
		}
	}
#endif

	int max_index = 0;
	for(i = 1; i < 10; i++){
		if(s[i] > s[max_index]){
			max_index = i;
		}
	}
	printf("最大值 %d, 最大值的下标 %d\n", s[max_index], max_index);
	return 0;
}

2. 斐波那契数列

1 1 2 3 5 8 13 21 。。。。。

定义一个 int 数组,长度为20,保存 斐波那契数列的前20位,并输出。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int fb[20] = {1,1};
	int i = 0;
#if 0
	for(i = 2; i < 20; i++){
		fb[i] = fb[i-1] + fb[i-2];
	}
#endif

	for(i = 0; i < 18; i++){
		fb[i+2] = fb[i+1] + fb[i];
	}

	for(i = 0; i < 20; i++){
		printf("%d  ",fb[i]);
	}
	putchar(10);

	return 0;
}

二、二维数组

1. 概念

所谓的二维数组,就是有两个下标的数组。

2. 定义二维数组的格式

存储类型 数据类型 数组名[行数][列数];

如 int s[3][4]; //定义了一个二维数组,有3行 4 列 共计12个元素,每个元素都是一个 int类型

注意:虽然二维数组有行号和列号,但是二维数组的成员在内存上也是连续的。

其中列宽,决定了数组按行偏移时的跨度。

二维数组访问元素:

数组名[行号][列号]; //行号和列号都是从0开始的

s[0][0] s[0][1] s[0][2] s[0][3]

s[1][0] s[1][1] s[1][2] s[1][3]

s[2][0] s[2][1] s[2][2] s[2][3]

例:

#include <stdio.h>

int main(int argc, const char *argv[])
{
	//定义了一个二维数组  有2行 3列 共计6个元素 每个元素都是一个 int 类型
	int s[2][3];

	//访问二维数组 使用 数组名[行号][列号]
	s[0][0] = 10;
	s[0][1] = 20;
	s[0][2] = 30;
	s[1][0] = 40;
	s[1][1] = 50;
	s[1][2] = 60;
	printf("s[0][0] = %d\n", s[0][0]);//10
	printf("s[1][1] = %d\n", s[1][1]);//50

	//二维数组的数组名也时常量 不可以被赋值 也不可以 ++
	//s++; //错误的
	
	//二维数组的大小 = 行数 * 列数 * sizeof(元素类型)
	printf("sizeof(s) = %ld\n", sizeof(s));// 2 * 3 * sizeof(int) = 24


	//二维数组在内存上也时连续的
	int i = 0;
	int j = 0;
	for(i = 0; i < 2; i++){
		for(j = 0; j < 3; j++){
			printf("%p  ", &s[i][j]);
		}
		printf("\n");
	}

	printf("--------------------------------------\n");
	//二维数组的遍历
	//外层循环控制行数
	for(i = 0; i < 2; i++){
		//内层循环控制列数
		for(j = 0; j < 3; j++){
			printf("%d  ", s[i][j]);
		}
		printf("\n");
	}

	return 0;
}

3 .二维数组的初始化

#include <stdio.h>

int main(int argc, const char *argv[])
{
	//二维数组如果没有初始化,里面也是 随机值
	//int s[3][4];
	
	//二维数组初始化的方式
	//方式1:以行为单位 完全初始化
	/*
	int s[3][4] = {{1,2,3,4},
					{5,6,7,8},
					{9,10,11,12}};
	*/

	//方式2:以行为单位 不完全初始化
	//----没有初始化的位 默认用0初始化
	/*
	int s[3][4] = {{1,2},
					{5},
					{9,10,11}};
	*/

	//方式3:不以行为单位 完全初始化
	//int s[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
 
	//方式4:不以行为单位 不完全初始化
	//----没有初始化的位 默认用0初始化
	//int s[3][4] = {1,2,3,4,5}; 
	
	//方式5:全部初始化成0
	//int s[3][4] = {0};
	
	//方式6:省略下标的初始化方式
	//列宽是不能省略的  行号是可以省略的
	//并且不足一行的,也会自动根据列数分配一整行,不够的位用0初始化
	int s[][4] = {1,2,3,4,5,6,7,8,9};

	printf("sizeof(s) = %ld\n", sizeof(s));//48 说明是按整行分配的

	int i = 0;
	int j = 0;
	for(i = 0; i < 3; i++){
		for(j = 0; j < 4; j++){
			printf("%d  ", s[i][j]);
		}
		printf("\n");
	}

	return 0;
}

练习:

1.定义个 3行 4列的二维数组,并完全初始化,

输出数组中最大的元素,及最大元素的行号 列号。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int s[3][4] = {1,2,3,4,5,6,100,8,9,10,11,12};

	int i = 0;
	int j = 0;
	int max_row = 0;//最大值的行号
	int max_clum = 0;//最大值的列号
	for(i = 0; i < 3; i++){
		for(j = 0; j < 4; j++){
			if(s[i][j] > s[max_row][max_clum]){
				max_row = i;
				max_clum = j;
			}
		}
	}
	//当循环结束时,max_row 里面记录的就是最大值的行号
	//max_clum 里面记录的就是最大值的列号
	printf("max_value = %d   max_row = %d   max_clum = %d\n",\
			s[max_row][max_clum], max_row, max_clum);

	return 0;
}

2.使用二维数组保存 杨辉三角 ,并输出

	    1
		1	1
		1	2	1
		1	3	3	1
		1	4	6	4	1
		1	5	10	10	5	1
		1	6	15	20	15	6	1
		1	7	21	35	35	21	7	1
		1	8	28	56	70	56	28	8	1
	    1	9	36	84	126	126	84	36	9	1

答案:

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int s[10][10] = {0};
	s[0][0] = 1;
	int i = 0;
	int j = 0;
	for(i = 1; i < 10; i++){
		s[i][0] = 1;
		for(j = 1; j < 10; j++){
    		s[i][j] = s[i-1][j]+s[i-1][j-1];
		}
	}
	
	for(i = 0; i < 10; i++){
		for(j = 0; j <= i; j++){
			printf("%-4d", s[i][j]);
		}
		putchar(10);
	}

	return 0;
}

三、字符数组和字符串

#include <stdio.h>

int main(int argc, const char *argv[])
{
	//可以使用字符数组来保存一组字符
	char s1[5] = {'A','B','C','D','E'};

	//一维数组的遍历
	int i = 0;
	for(i = 0; i < 5; i++){
		printf("%c", s1[i]);
	}
	putchar(10);

	//可以将字符串保存在字符数组里
	char s2[32] = {"www.hqyj.com"};
	printf("s2 = %s\n", s2);
	char s3[32] = "www.hqyj.com";//两种写法都可以  一般是用下面这种
	printf("s3 = %s\n", s3);
	printf("sizeof(s3) = %ld\n", sizeof(s3));//32
	
	//字符串结尾都会有一个隐藏的 '\0' 来标识字符串结束
	//所以自己定义数组保存字符串时  要给 '\0' 留一个字节的空间
	char s4[] = "helloworld";
	printf("sizeof(s4) = %ld\n", sizeof(s4));//11

	//C语言处理字符串 遇到 '\0' 表示结束
	char s5[32] = "hello\0world";
	printf("sizeof(s5) = %ld\n", sizeof(s5));//32
	printf("s5 = %s\n", s5);//hello
	printf("s5[6] = %c\n", s5[6]);//w  说明\0后面的 world 也存到数组里了
									//只不过printf输出时 遇到 \0 就结束了
	
	//如果时字符数组的话 不要使用 %s 输出
	printf("s1 = %s\n", s1);//因为s1中没有 \0 所以printf会一直向后找
							//直到遇到 \0 结束
							//数组访问会越界,出现的错误 不可预知
	
	//如果非要用%s输出  需要在结尾加个  \0
	//	'\0'  0   '0'  三个零是不一样的
	//   '\0'  0  一样的  ascii码都是 0
	//   '0'  ascii码是  48
	char s6[6] = {'A','B','C','D','E','\0'};
	printf("s6 = %s\n", s6);

	return 0;
}

四、字符串处理函数

1.strlen()

功能:

计算字符串的长度,不包括 '\0'

头文件:

#include

函数原型:

size_t strlen(const char *s); //size_t 是 unsigned int 的别名

参数:

要计算长度的字符串的首地址

返回值:

字符串的长度

#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	char s1[32] = "hello world";
	int ret = strlen(s1);//如果需要用到结果  可以使用变量保存
	printf("sizeof(s1) = %ld\n", sizeof(s1));//32
	printf("strlen(s1) = %ld\n", strlen(s1));//11
	printf("ret = %d\n", ret);//11

	//如果是字符数组 要慎用 strlen计算长度
	//因为 strlen 也时遇到 '\0' 才结束的
	char s2[5] = {'A','B','C','D','E'};
	printf("strlen(s2) = %ld\n", strlen(s2));//结果不可预知

	return 0;
}

练习:

自己写代码实现 strlen 的功能。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	char s[32] = "hello world";
	int i = 0;
	//while(s[i]){  //这样写也可以
	while(s[i] != '\0'){
		i++;
	}
	printf("mystrlen(s) = %d\n", i);

	return 0;
}

2.strcpy

功能:

将src 拷贝到 dest 里面

头文件:

#include

函数原型:

char *strcpy(char *dest, const char *src);

参数:

dest : 目的字符串

src : 源字符串

返回值:

目的字符串

#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	char s1[32] = "hello world";
	char s2[32] = "hqyj";
	printf("s1 = %s\n", s1);//hello world
	printf("s2 = %s\n", s2);//hqyj

	//将s1的字符串拷贝到 s2 中
	//注意:s2 要足够大 否则可能出现 访问越界
	strcpy(s2, s1);

	printf("-----------------------------\n");
	printf("s1 = %s\n", s1);//hello world
	printf("s2 = %s\n", s2);//hello world

	char s3[32] = "kjasshdjkfka";
	char s4[32] = "abcd";
	strcpy(s3, s4);//s4只会覆盖s3的前5位 分别替换成 abcd \0
					//s3 后面的内容还在里面,只是处理不到了
	printf("s3 = %s\n", s3);//abcd
	printf("s4 = %s\n", s4);//abcd
	printf("s3[4] = %d  [%c]\n", s3[4], s3[4]);//0
	printf("s3[5] = %d  [%c]\n", s3[5], s3[5]);//h

	return 0;
}

练习:

自己写代码实现 strcpy 的功能。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	char s1[32] = "hqyj";
	char s2[32] = "hello world";

	printf("s1 = %s\n", s1);
	printf("s2 = %s\n", s2);

	printf("----------------------------\n");

	int i = 0;
	//只要 s2 没遇到 '\0'  就将字符复制给 s1
	while(s2[i] != '\0'){
		s1[i] = s2[i];
		i++;
	}
	s1[i] = s2[i];//将 s2 的 '\0' 也拷贝给 s1 !!!!

	printf("s1 = %s\n", s1);
	printf("s2 = %s\n", s2);

	return 0;
}

3. strcat

功能:

将src 追加到 dest 后面,会覆盖dest的 '\0'

头文件:

#include

函数原型:

char *strcat(char *dest, const char *src);

参数:

dest : 目的字符串

src : 源字符串

返回值:

目的字符串

#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	char s1[32] = "hello world";
	char s2[32] = "1234";

	printf("s1 = %s\n", s1);
	printf("s2 = %s\n", s2);

	//注意:s1 要足够大 否则可能出现访问越界
	strcat(s1, s2);

	printf("-----------------------------\n");
	printf("s1 = %s\n", s1);//hello world1234
	printf("s2 = %s\n", s2);//1234

	return 0;
}

练习:

自己写代码实现 strcat 的功能。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	char s1[32] = "hello world";
	char s2[32] = "1234";
	
	int i = 0;
	int j = 0;
	//先找 s1 的 '\0' 的下标
	while(s1[i]){
		i++;
	}
	
	//从s1 的 '\0' 开始覆盖
	while(s2[j]){
		s1[i+j] = s2[j];
		j++;
	}

	//将s2 的 '\0' 也追加给 s1
	s1[i+j] = s2[j];

	printf("s1 = %s\n", s1);

	return 0;
}

4.strcmp

功能:

比较两个字符串的大小,

比较的是第一个不相等的字符的 ascii 码

注意:不是比较长度!!!

头文件:

#include

函数原型:

int strcmp(const char *s1, const char *s2);

参数:

要参与比较的两个字符串

返回值:

>0 s1>s2

==0 s1==s2

#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	char s1[32] = "helloakjdshfjkahsdkjfh";
	char s2[32] = "helzo";
//strcmp 会一位一位的比较两个字符串对应字符的ascii码
//直到出现大小关系,就立即返回
	int ret = strcmp(s1, s2);
	if(ret>0){
		printf("s1>s2\n");
	}else if(ret<0){
		printf("s1<s2\n");
	}else{
		printf("s1==s2\n");
	}

	//返回的实际是两个字符串中第一个不相等的字符的 ascii码的差值(s1-s2)
	printf("%d\n", ret);
	printf("%d\n", 'l'-'z');

	return 0;
}

练习:

自己写代码实现 strcmp 的功能。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	char s1[32] = "hello";
	char s2[32] = "hello";

	int i = 0;
	int ret = 0;
	while(s1[i]!='\0' && s2[i]!='\0'){
		ret = s1[i] - s2[i];
		if(ret != 0){
			break;
		}
		i++;
	}
	//上面的循环如果结束了,有两种情况
	//一种是 有字符串已经处理到 '\0'
	//另一种是提前 break 了
	
	//循环结束后 重新获取一下当前第i位的差值
	ret = s1[i] - s2[i];

	if(ret > 0){
		printf("s1>s2\n");
	}else if(ret < 0){
		printf("s1<s2\n");
	}else{
		printf("s1==s2\n");
	}

	return 0;
}

带 n 版本的函数

strncpy 表示将src的前n位 拷贝给 dest

strncat 表示将src的前n位 追加给 dest

strncmp 表示之比较两个字符串的 前 n 位

五、冒泡排序法

1.基本思想:

相邻的两个元素之间进行比较,按照要求进行交换。

2.详细步骤:(以升序为例 从小到大)

第一趟排序:

将第一个元素和第二个元素进行比较,将较大放在后面,

然后第二个元素和第三个元素进行比较,将较大的放在后面,

依次类推,直到第一趟排序结束,最大的元素就在最后一位了

第二趟排序:

将第一个元素和第二个元素进行比较,将较大放在后面,

然后第二个元素和第三个元素进行比较,将较大的放在后面,

依次类推,直到第二趟排序结束,第二大的元素就在倒数第二位了

依次类推,直到最后一趟排序完成,整个序列就有序了。

冒泡排序动图:

 3.代码实现:

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int s[10] = {12,34,5,3,6,45,67,98,55,1};
	int i = 0;
	int j = 0;
	int temp = 0;
	int len = sizeof(s)/sizeof(s[0]);

	//排序前
	for(i = 0; i < 10; i++){
		printf("%d  ",s[i]);
	}
	putchar(10);
#if 0
	//第一趟排序
	//因为时 第i和第i+1位比的  所以 i 只需要能访问到倒数第二个元素就行了
	for(i = 0; i < len-1; i++){
		//前面比后面大时  进行交换
		if(s[i] > s[i+1]){
			temp = s[i];
			s[i] = s[i+1];
			s[i+1] = temp;
		}
	}
#endif

#if 0
	//外层循环控制比较的趟数
		//当只剩下最后一个元素时,就不用再比了 所以 可以少比一趟
	for(j = 0; j < len-1; j++){
		//内层循环用来找每趟的最大值
			//因为每趟都能确定一个最大值,所以每趟都可以少比一个元素 所以 -j
		for(i = 0; i < len-1-j; i++){
			if(s[i] > s[i+1]){  //如果想降序排序,只需将此处的 > 改成 < 即可
				temp = s[i];
				s[i] = s[i+1];
				s[i+1] = temp;
			}
		}
	}
#endif 

//更优化的写法:有些场景  数据不一定需要比到最后
//才能确定有序,可能比到中途就已经有序了,如下面的数据
//1  2  3  4  5  6  8   7  10  9
//这时,对已经有序的数据再进行比较  就是多余的操作了
//优化方式:使用标志位确定数据是否已经有序,代码优化如下:
	int flag = 0;//用于判断是否已经有序的标志位 0 有序  1 无序
	for(j = 0; j < len-1; j++){
		flag = 0;//每趟开始时 我们都认为是已经有序了
		for(i = 0; i < len-1-j; i++){
			if(s[i] > s[i+1]){
				temp = s[i];
				s[i] = s[i+1];
				s[i+1] = temp;
				flag = 1;//如果发生交换,说明我们认为的有序是错的 将flag 置1
			}
		}
          //如果没有发生交换,flag仍然为0 就说明数据已经有序了
		if(0 == flag){
			break;
		}
	}

//排序后
	for(i = 0; i < 10; i++){
		printf("%d  ",s[i]);
	}
	putchar(10);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值