概念
数组是用来保存一组相同数据类型的数据的,是一个构造类型;
数组中的每个数据称为数组的元素或者数组的成员;
数组中每个元素在内存上都是连续的,不管几维数组,都是连续的。
一维数组
2.1 概念
所谓的一维数组,就是下标只有一个的数组。
一维数组的元素,在内存上是连续的。
2.2 定义一维数组的格式
存储类型 数据类型 数组名[下标];//int s[5];
存储类型:不写默认就是 auto
数据类型:表示数组中每个元素的数据类型
数组名:是一个标识符,要符合标识符的命名规范
下标:在定义数组时,下标一般都是常量,表示数组中元素的个数
在其他场景下,可以是常量、也可以是变量、也可以是表达式
表示访问数组中的哪个元素
2.3 一维数组的性质
int s[5]; //定义了一个一维数组,数组名叫s,数组中共有5个元素,每个元素都是一个int类型的变量。
一维数组的大小 = 单个元素的大小 * 元素的个数:
printf("sizeof(s) = %ld\n", sizeof(s)); //20 == sizeof(int) * 5
一维数组访问元素的方式:数组名[下标] ,注意下标从0开始,当取出数组中某个元素之后,对他的操作和对普通的单个变量操作是一模一样的。
注:数组名是常量 不能被赋值 也不能++:
int s2[5];
//s2 = s;//错误的
//s2++; //错误的
数组一旦定义好了 就不能整体赋值了,只能一位一位的赋值。
数组的元素在内存上是连续的。
printf 使用 %p 可以将数据按地址的方式输出,& 可以获取变量的地址
遍历一维数组:
int i = 0; //用循环变量做为数组的下标
//for(i = 0; i < 5; i++){
for(i = 0; i < sizeof(s)/sizeof(s[0]); i++){
printf("%d ", s[i]);
}
2.4 一维数组的初始化
对照后面的字符数组等
一维数组如果不初始化,里面每个元素都是随机值
完全初始化,例:
int s[5] = {1, 2, 3, 4, 5};
不完全初始化,这种方式是从左到右依次初始化 没有初始化的元素默认都是0,例:
int s[5] = {1, 2};
全部初始化成0 ——最常用的用法,例:
int s[5] = {0};
省略下标的初始化,这种方式,编译器会根据给定数据的个数自动计算长度:
int s[] = {1, 2, 3, 4, 5, 6};
2.5 关于数组越界访问的问题
数组越界访问的问题编译器不会检查,需要程序员自己检查;
可能不报错;可能段错误;可能修改了不该修改的数据;
数组越界导致的错误是不可预知的。
2.6冒泡排序(必须记住)
代码实现
#include <stdio.h>
int main(){
int s[10] = {12, 34, 43, 56, 87, 55, 120, 98, 6, 4};
int len = sizeof(s)/sizeof(s[0]);
int i = 0;
int j = 0;
int temp = 0;
//排序前
for(i = 0; i < len; i++){
printf("%d ", s[i]);
}
printf("\n");
//外层循环控制趟数
for(j = 0; j < len-1; j++){ //此处的-1是最后一趟只有一个元素了 不用排序了
//内层循环控制每趟排序
for(i = 0; i < len-1-j; i++){ //此处的-1是为了防止越界的
//此处的 -j 是因为每趟都能确定好一个元素的位置
//可以减少比较的次数 提高效率
if(s[i] > s[i+1]){//如果是降序 只需将此处的 > 改成 < 即可
temp = s[i];
s[i] = s[i+1];
s[i+1] = temp;
}
}
}
//排序后
for(i = 0; i < len; i++){
printf("%d ", s[i]);
}
printf("\n");
return 0;
}
二维数组
3.1 概念
所谓的二维数组,就是下标有两个的数组。
3.2 定义二维数组的格式
存储类型 数据类型 数组名[行数][列数]; //int s[3][4];
二维数组的元素在内存上也是连续的。
二维数组的本质也是一维数组,多了一个行号,只是多了一种按行操作的方式而已.
二维数组的列数很重要,因为他决定了按行操作时的跨度。
3.3 二维数组的性质
int s[3][4]; //定义了一个二维数组,数组名叫s,数组中共有3行4列 共计 12个元素,每个元素都是一个 int 类型的变量。
二维数组的大小 = 单个元素的大小 * 行数 * 列数;
二维数组访问元素的方式:数组名[行号][列号] 。注:行号和列号都是从0开始的;
当取出二维数组的一个元素后对该元素的操作和对单个变量的操作是一模一样的。
二维数组的数组名也是一个常量 不能被赋值 也不能++,例:
s = 1234; //错误的
s++; //错误的
遍历二维数组:
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");
}
二维数组的元素在内存上也是连续的
4.4 二维数组的初始化
二维数组如果没有初始化 里面也是随机值;
以行为单位:
完全初始化:
int s[3][4] = {{1,2,3,4},{5,5,6,7},{9,10,11,12}};
不完全初始化,没有初始化的元素 默认用0初始化:
int s[3][4] = {{1,2},{3,4},{5}};
不以行为单位
完全初始化:
int s[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
不完全初始化,没有初始化的元素 默认用0初始化:
int s[3][4] = {1,2,3,4,5};
全部初始化成0——最常用的用法:
int s[3][4] = {0};
省略下标的初始化,行可以省略,列不可以省略 ,这种写法即使给的元素不够一整行了,也会按整行分配空间,没有初始化的元素默认用0初始化:
int s[][4] = {1,2,3,4,5,6,7,8,9};
遍历二维数组:
int i = 0;
int j = 0;
for(i = 0; i < 3; i++){
for(j = 0; j < 4; j++){
printf("%d ", s[i][j]);
}
字符数组和字符串
字符数组:数组每个元素都是一个 char 类型的变量。
将字符串存在字符数组中,可以有下面的写法:
(1)写法1
char s2[6] = {"abcde"}; //注意字符串结尾都有隐藏的 '\0'
//要多分配一个字节给 '\0'用 否则越界
printf("s2 = [%s]\n", s2); //abcde
(2)写法2
char s3[6] = "world"; //{}可以省略
printf("s3 = [%s]\n", s3); //world
(3)写法3
char s4[] = "beijing"; //会根据字符串的长度 自动计算计算空间大小
//会 将 '\0' 算进去
printf("s4 = [%s]\n", s4);//beijing
printf("sizeof(s4) = %ld\n", sizeof(s4));//8
注意:如果不是字符串,就不能按字符串的方式操作,如:不能使用 printf的 %s 输出。%s 将后面的数据按字符串的方式输出,直到遇到 '\0' 才结束 如果没有遇到 就一直往后找
printf("s1 = [%s]\n", s1);结果是不可预知的,这种方式可以按字符串的方式操作,因为不完全初始化,后面都是 0,而 0 就是 '\0'
注意 0 '\0' '0' 的区别,0 和 '\0' 是一样的 ascii码都是 0,'0'的ascii码是 48。
字符串处理函数
strlen strcpy strcat strcmp
5.1 strlen
strlen函数的功能:计算字符串的长度,不包括结尾的'\0'。
头文件:
#include
函数原型:
size_t strlen(const char *s);
参数:
就是要计算长度的字符串的首地址
返回值:
计算的结果
例:
可以直接将结果输出
char s1[32] = "hello";
printf("strlen(s1) = %ld\n", strlen(s1)); //5
也可以定义变量保存计算的结果供后面使用
int ret = strlen(s1);
printf("ret = %d\n", ret);//5
strlen遇到'\0'就结束了
char s2[32] = "beijing\0hqyj";
printf("strlen(s2) = %ld\n", strlen(s2));//7
如果不是字符串就不能使用 strlen 计算长度了
//char s3[5] = {'h', 'e', 'l', 'l', 'o'};
//printf("strlen(s3) = %ld\n", strlen(s3));//不可预知的
要注意 strlen 和 sizeof 的区别:
strlen 是 函数 是计算第一个'\0'之前字符的个数
sizeof 是 C语言的关键字 是计算占用的内存空间的大小的
5.2strcpy
函数的功能:
将src拷贝给dest 包括src的'\0'。注:目标字符串dest要足够大
头文件: #include
函数原型:
char *strcpy(char *dest, const char *src);
参数:
dest:目标字符串
src:源字符串
返回值:目标字符串----一般不使用。
例:
char s1[32] = "hello world";
char s2[32] = "beijing";
strcpy(s1, s2); //将 s2 拷贝给 s1
//要保证 s1 足够大 否则越界访问
printf("后 s1 = [%s]\n", s1);//beijing
printf("后 s2 = [%s]\n", s2);//beijing
拷贝之后,原来目标字符串中多出来的部分还在里面,只不过通过字符串的方式访问不到了
printf("s1[8] = %c\n", s1[8]);//r
printf("s1[9] = %c\n", s1[9]);//l
printf("s1[10] = %c\n", s1[10]);//d
也可以直接将字符串常量拷贝给数组:
char s3[32] = {0};
strcpy(s3, "hello");
printf("s3 = [%s]\n", s3);//hello
5.3 strcat
函数的功能:
将src追加到dest后面,会覆盖dest结尾的'\0',注:要保证dest足够大
头文件:#include
函数原型:char *strcat(char *dest, const char *src);
参数:
dest:目标字符串
src:源字符串
返回值:目标字符串----一般不使用
例:
char s1[32] = "hello";
char s2[32] = "beijing";
strcat(s1, s2);//将s2追加到s1后面 注意s1要足够大
printf("后 s1 = [%s]\n", s1);//hellobeijing
printf("后 s2 = [%s]\n", s2);//beijing
5.4 strcmp
函数的功能:比较两个字符串中字符的ascii码,直到出现大小关系时立即返回,只有两个字符串中第一个'\0'之前所有字符都相等,才认为两个字符串相等
头文件:#include
函数原型:int strcmp(const char *s1, const char *s2);
参数:s1和s2就是要参与比较的两个字符串
返回值:
0 s1==s2
>0 s1>s2
0< s1<s2