数组及其定义
数组:将若干个相同数据类型的变量存放在一个连续的内存空间
数组中的每一个元素都是一个变量
构造类型:将基本类型构建成的类型
数组:相同类型的数据存放在安装一个集合中,这种的构造类型是数组
定义
// 数组名和变量名定义方法一样
//符号与[]结合代表这个是一个数组
//数组中的元素的个数由[]里面的数值决定
//每个元素的类型,数组名前面的类型决定
//1.定义数组时,[]里面的值不能为变量,只能为常量
//2.使用时,[]里面的值可以为常量也可以是变量
//数值数组不能整体操作
//数组的每一个元素都是变量,可以被改变赋值
int n = 10;
int num[10];
//num[0] = 100;
//printf("%d\n",num[0]);
for (int i = 0; i < 10; i++)
{
printf("%d\n", num[i]);
}
system("pause");
数组初始化
// 如果数组只初始化部分元素,其他元素被初始化为0
int num[10] = {1,2}
// int a[] = 5; err 定义时没有告知有几个元素
//如果定义时,[]中没有值,这个数组的元素个数由{}里面的元素个数决定
int num[] = { 1,2,3 };
// 数组大小
//num是数组名,代表这个数组
int num[10] = { 1,2,3,4,5,6,7,8,9,10 };
// num就代表这个数组的类型,也就是int [10]
printf("%d\n",sizeof(int [10]));
printf("%d\n", sizeof(num));
//求数组元素个数
int n = sizeof(num) / sizeof(num[0]);
数据在内存中的地址
启动一个程序,系统会给这个程序分配一块内存空间,内存的最小单位是1个字节,内存中的每一个字节都会有编号,这个编号即为内存的地址
数据在内存中的地址,就是它在内存中的起始地址
如下所示,
char a;
int b;
// 一个int是32位,也就是4个字节,占四个内存单元
&b = 0x1001
数组的地址和数组名
int a[10]
数组名a等价于第0个元素的地址(首元素地址)
因为其是一个地址,也就是常量,所以不能被赋值
&a[0] -> 第0个元素的地址
&a -> 整个数组的地址
int a[5];
a[0] -> 第0个元素
&a[0] -> 第0个元素的地址 == 01
-
a == &a[0] == 01
数组名a 代表数组,也代表第0个元素的地址
所以说数组名是一个常量,是一个地址 -
&a == 01
整个数组的地址 ,在数值上, &a[0],a,&a相等
&a[0]+1 == 05 : 元素的地址加1跨过一个元素
a+1 == 05 : 元素的地址加1跨过一个元素
因为a=&a[0]+1,都是代表元素的地址加1
&a+1 == 21 : 整个数组的地址加1跨过整个数组
二维数组与数组名
int a[2]/[4]定义了一个二维数组,其有2个一维,每个一维数组有4个元素
额日为数组的a[0]代表第0行
int a[2][3];
a[0][0]; // 第0行第0个元素
&a[0][0]== 01; // 第0行第0个元素的地址
a[0]; // 代表第0个一维数组的数组名,a[0]=&a[0][0]
&a[0]; // 第0行的地址 = 01
a; // 二维数组的数组名,代表二维数组,也代表首行地址&a[0]
&a; // 二维数组的地址
&a[0][0]+1; // 元素地址加1,跨过一个元素
a[0]+1; // 元素地址加1,跨过一个元素
&a[0]+1; // 行地址加1,跨过一行
a+1; // 行地址加1,跨过一行
&a+1; // 二维数组地址加1,跨过整个数组
字符数组
- C语言中没有字符串这种数据类型,可以通过char的数组来代替
- 字符串一定是一个char的数组,但char的数组未必是字符串
- 数字0(和字符‘\0’等价)结尾的char数组就是一个字符串,但如果char数组没有以数字0结尾,那么就不是一个字符串,只是普通字符数组。所以字符串是一种特殊的char的数组
// printf("%s")接收一个起始地址,打印到0(0在内存中以'\0'存储)停止
.
int main()
{
char c1[] = { 'c', ' ', 'p', 'r', 'o', 'g' }; //普通字符数组
printf("c1 = %s\n", c1); //乱码,因为没有’\0’结束符
//以'\0'('\0'就是数字0)结尾的字符数组是字符串
char c2[] = { 'c', ' ', 'p', 'r', 'o', 'g', '\0'};
char a[5] = "word"; // 定义了一个字符数组,存的是word\0
// char a[] = "word"; 这样定义也可以
printf("c2 = %s\n", c2);
//字符串处理以‘\0’(数字0)作为结束符,后面的'h', 'l', 'l', 'e', 'o'不会输出
char c3[] = { 'c', ' ', 'p', 'r', 'o', 'g', '\0', 'h', 'l', 'l', 'e', 'o', '\0'};
printf("c3 = %s\n", c3);
return 0;
}
字符串的初始化
int main(){
// 不指定长度,没有0结束符,有多少个元素,就有多长
char buf[] = {'a', 'b', 'c'};
printf("buf = %s\n", buf); //乱码
// 指定长度,后面没有赋值的元素,自动补0
char buf2[] = {'a', 'b', 'c'};
char buf[1000] = {"hello};
printf("buf2 = %s\n", buf2);
//使用字符串初始化,编译器自动在后面补0,常用
char buf8[] = "agjdslgjlsdjg";
// 初始化并赋值0
char str[128] = "";
// 这里好好看看
char buf5[50] = { '1', 'a', 'b', '0', '7' };
printf("buf5 = %s\n", buf5); // 1ab07+乱码,因为后面没有结束符0或者'\0'
char buf6[50] = { '1', 'a', 'b', 0, '7' };
printf("buf6 = %s\n", buf6); // 1ab 到0结束
char buf7[50] = { '1', 'a', 'b', '\0', '7' };
printf("buf7 = %s\n", buf7); // 1ab
// 0 和 '\0'是等价的
}
读取字符串
scanf %s缺点:
- 遇到\n结束,遇到空格结束
- 如果存放读取字符的空间不足,继续将后存放,会造成内存污染
gets()
gets()遇到空格不结束,遇到/n才结束
// gets是一个库函数,从键盘读取字符串
int main()
{
//gets遇到\n结束.,但是遇到空格不结束读取空格
//gets也会造成内存污染
char num[5] = "";
gets(num);//()里面的参数要的是存放读取字符串的地址
printf("num=%s\n",num);
system("pause");
return 0;
}
fgets() 这个比较好用
库函数:从键盘读取一个字符串
相对于scanf和gets不会污染内存,(安全),但是fgets也会将\n读入
char num[128];
// fgets从stdin(标准输入-键盘)读取字符串到nujm数组中,
// 最大可以读sizeof(num)-1个字符
fgets(num, sizeof(num), stdin);
strlen()
测字符数组有效字符的个数
int main()
{
char buf[128] = "helloA";//buf[5]=0;
//需要找到最后一个字符的下标
//求的是字符数组有效字符的个数
int i = 0;
/*while (buf[i] != '\0')
{
i++;
}
printf("i=%d\n",i);*/
i = strlen(buf);//strlen()测字符数组有效字符的个数
printf("i=%d\n", i);
buf[i - 1] = '\0';
// 将最后的换行变为0
buf[strlen(buf) - 1] = 0;
printf("%s\n",buf);
system("pause");
return 0;
}