数组
组成
- 数组名:
- 下标:索引,本质是元素距离首地址(第一元素)的偏移量,以首地址为参照,可使用数组名 + 偏移量访问,下标越大,地址编号越大
- 元素:数组中每一个匿名的变量空间,每一块空间都有一个独有的地址
- 特征:在内存里开辟一段连续的相同类型的空间,数组的数据称为元素,同一数组的类型相同
一维数组
数据类型 数组名[ 数组大小 ];
int a[10];
#define NUM 4
int array[NUM];
int num = 5;
int arr[num];
int a[60*30];
-
数据类型有元素决定,数组名等同于数组变量
-
数组容量值为整数,可以是常量和符号常量,不能是变量。
-
定义数组相当与申请一个 连续的 用于容纳指定元素数量 内存单元;相当于定义多个匿名的变量,通过
数组名[下标]
访问 -
申请数组后, 最大下标为数组元素个数,最小为零;未初始化时,数组内为随机值
数组访问
- 数组需要通过 数组名[ 下标 ] 访问元素,单个访问
int arr[10]; //定义数组
arr[0] = 89; //数组第一个为89
int a = a[0]; //通过变量访问元素
int c = arr[9];
int b = arr[10];//下标越界
int len = sizeof(arr) / sizeof(a[0]); //sizeof 返回字节大小
数组访问不能越界
初始化
数据类型 数组名[数组大小] = {常量};
- 数组可以部分初始化,给前几个元素初始化,未被初始化自动初始化
- 定义数组时,未定义数组容量,系统会根据初始化元素个数决定数组大小
int arr[10] = {1,5,3,6,4};
int arr[10] = {1,8,8,2,6,7,1};
int a[] = {1,3,6,9,4,5,8};
-
柔性数组:
-
C99,针对结构体的最后一个成员可以是一个未指定大小的数组
-
数组容量待定或者待确定的数组
int a[] = {1,2,3,6,5,4};
冒泡排序
-
一次指排序一个数,长度为n时,最差需要 n-1 次排好
-
每次排序需要两数比较,将较大或较小数据向后移动交换,比较完成时,较大的或较小的数出现在结尾。
-
每轮比较次数
= 元素个数 - 轮数 - 1(因为下标为0)- 从后向前:1 2 3 4
5
-> 1 2 35
4 -> 1 25
3 4 -> 15
2 3 4 ->5
1 2 3 4 (第一轮比4次)
- 从后向前:1 2 3 4
#include <stdio.h>
int a[10] = {0};
//向后
void bh(int a[])
{
int swap = 0;
for(int i = 0;i < 10-1;i++)
{
for(int j = 0; j< 9 -i;j++)
{
if(a[j] > a[j+1])
{
swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
}
}
}
int main(int argc,char *argv[])
{
int num = 0;
printf("输入 10 个整数:");
for(int i = 0 ;i <= 10;i++)
{
scanf("%d",&num);
a[i] = num;
b[i] = num;
}
bh(a);
printf("the result : ");
for(int i = 0;i < 10;i++)
{
printf("%d ",a[i]);
}
printf("\n");
return 0;
}
//输入一个日期,计算该日是该年的第几天
/*
1.创建一个数组用于存放一个月的天数,二月为0
2.闰年判断
3.使用变量存放天数
4.前面的月天数 + 该天的日期
*/
#include <stdio.h>
int evy[] = {0,31,0,31,30,31,30,31,31,30,31,30,31};//0月
int check(int y,int m)
{
if((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0))
return 1;
else
return 0;
}
int main(int argc,char *argv[])
{
int year= 0, month = 0, day = 0;
printf("请输入 年 月 日 :");
scanf("%d %d %d",&year,&month,&day);
int sum = day;
if(check(year,month))
evy[2] = 29;
else
evy[2] = 28;
for(int i = 0;i < month;i++)
{
sum += evy[i];
}
printf("这个月有%2d天 \n",sum);
return 0;
}
二维数组
-
本质是行列式,使用二维数组由 行和列 两部分组成
-
二维数组可视为 元素是一维数组 的一维数组
-
列数可视为 元素数组的长度(不可省略)
数据类型 数组名 [行数][列数] ;
int arr[2][3] = {{11,12,13},{21,22,23}};
int arr2[2][3] = {11,12,13,21,22,23};
int arr3[][3] = {{11,12,13},{21,22,23}};//柔性数组,列数不能省略
int arr4[2][3] = {{11,12},{21}};
- 计算机中,数组的存储顺序是按行执行,即在遍历时按照arr2顺序
- 未初始化自动填充 0
#include <stdio.h>
//二维数组遍历
int main(int argc,char *argv[])
{
int arr[][3] = {{11},{21,22},{31,32,33}};
int r_len = sizeof(arr)/sizeof(arr[0]);
for(int i = 0;i < r_len;i++) //外层循环遍历行元素
{
int c_len = sizeof(arr[i]) / sizeof(int);
//获取各行元素个数
for(int j = 0;j < c_len;j++)
{
printf("%-2d ",arr[i][j]);
}
}
return 0;
}
#include <stdio.h>
//转置
int a[][3] = {{11,12,13},{21,22},{31,32}};
int b[3][3];
int main(int argc,char *argv[])
{
int r_len = sizeof(a) / sizeof(a[0]);
for(int i = 0;i < r_len;i++)
{
int c_len = sizeof(a[i]) / sizeof(a[0][0]);
for(int j = 0;j < c_len;j++)
{
b[j][i] = a[i][j];
}
}
for(int i = 0;i < sizeof(b) / sizeof(b[0]);i++)
{
for(int j = 0;j < sizeof(b[i]) / sizeof(b[0][0]);j++)
{
printf("%-2d",b[i][j]);
}
}
return 0;
}
字符数组
-
元素类型为char字符型的数组,用于存储字符串数据
-
使用char表示一个字节
char a = 'L';
char c = 65;
char ch = "A"; //字符串
- C语言支持字符串常量,不支持字符串变量;单字节不能使用中文和字符串
char name[size] = "";
char name[][];
- 未初始化,元素不确定
- 占不满数组默认使用
'\0'
占位,空格使用'\32'
占位 - 字符的个数大于长度, 按照语法错误处理
- 字符个数和数组长度相同,可省略数组长度
char c[8] = {'h','e','l','l','o'};
char c[8] = {'h','e','l','l','o','\0','\0','\0'};
字符串
- 字符串以
'\0'
结束标志,有'\0'
就是字符串
char ch[] = {'c','h'}; //字符数组
char ch[] = {'c','h','\0'}; //字符串
char ch[] = "ch";
char ch[] = "hello\0love"; //输出遇到 '\0' 时表示字符串结束,长度11,即5+1+4+1
// \0 空字符
// 0 数字零 ascii为48
// 空格 ascii为32
-
用字符串常量,系统自动加上 ’\0’
-
用sizeof获取字符串大小
-
用strcpy() 赋值,不能用常量对字符串数据赋值
输入
- 使用%s输入输出时,输入输出为数组名
- 对于字符串操作,用到系统提供的函数(API操作)
scanf
scanf("%s",name); //char数组类型
- scanf传地址时,仅需要传变量名,数组名代表首地址
- 使用scanf时,不能出现空格,会自动加入
'\0'
fgets
fgets(name,size,FILE*);
- 从键盘输入一个字符串常量到字符数组,返回字符数组首地址 ,默认使用12位16进制
- 使用
fgets
可获取输入的字符串,包含\n
,忽略空格 - 如果输入的字符串不包括
空格和换行
使用scanf fgets
gets
gets(name);
输出
printf
printf("%s",name);
fputs
fputs(name,FILE*(stdout));
puts
puts(const char *s); //输出字符串,输出遇到和换行符号会换行
putchar
char ch = putchar(int);
字符串转数值
atoi
: 字符串转整型
int atoi(char *name);
-
strtol
:进制:默认十进制 16十六进制 0八进制 2二进制
long strtol(const char *name,char **endptr,进制);//stdlib
printf("%lo",strtol("12",NULL,8)); //10
字符串拼接
#include <string.h>
strcat(name,"内容"); //puts使用,内容为常量和name
- 内容不要超过name的容量,拼接为后加
- 连接后没有
\0
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
char name[20];
printf("input:");
fgets(name,sizeof(name),stdin);
strcat(name," hello");
fputs(name,stdin);
return 0;
}
字符串拷贝
strcpy(name,"str");
- 字符串赋值不能直接使用赋值字符串
- 使用strcpy给字符串复制赋值,覆盖复制
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
char name[20];
printf("input: ");
fgets(name,sizeof(name),stdin);
strcpy(name,"lu");
fputs(name,stdout);
return 0;
}
字符串比较
int num = strcmp(name,str);
- 不能用
==
比较 - 比较两串对应位置比较,从左向右字典序比较,遇到
\0
结束 - 若相等 返回值为1 ;name>str 返回正数;返回正数是比较的name相应位置的ascii大于str
- name和str可以是数组或常量
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
char name[20];
printf("input: ");
scanf("%s",name);
int num = strcmp(name,"lu");
if(!num)
{
fputs("\nsame\n",stdout);
}
return 0;
}
字符串长度
unsigned long int num = strlen(name);
-
返回包含的字符个数,不含
\0
-
在字符串中间有
\0
当作两个字符
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
char name[20];
fputs("input:",stdout);
scanf("%s",name);
unsigned int num = strlen(name);
printf("the len:%d",num);
return 0;
}