数组
数组是一种构造类型, 是由基本类型构造而成, 当我们想用一群变量来描述同一类相同的东西的时候, 比如100个年龄变量, 我们可以这样, int age 1; int age 2; int age 3......int age 100; 这样极不方便书写, 也不方便管理, 此时神奇的数组就出现了, int age[100], 轻轻松松搞定。
构造类型带来了书写和管理的方便, 我们将从定义, 大小, 初始化,访问内容进行展开...
1. 基本语法
#include <stdio.h>
int main()
{
// 数组类型统一
// 定义格式: 类型 数组名 [大小]
int arr[10];
// 数组也是有长度的
printf("len = %d\n", sizeof(arr));
// 数组的长度 = 总占用字节数 / 类型的字节数
printf("%d\n", sizeof(arr[0]));
printf("%d\n", sizeof(arr) / sizeof(arr[0]));
return 0;
}
2. 数组的初始化和赋值
-
在定义数组的同时进行赋值,称为初始化
-
全局数组若不初始化,编译器将其初始化为零
-
局部数组若不初始化,内容为随机值
凡是构造类型,要么在初始化的时候初始化, 要么对集合中的每个元素单独初始化。定义以后,不可以再以初始化的方式初始化。凡是基础数据类型,既可以在定义的时候初始化,也可以先定义后初始化。
#include <stdio.h>
int arr8[10];
int main()
{
// char str[100] = '123456';
// printf("%d\n",sizeof(str));
int arr[10];
// 获取数组长度
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
// 给数组赋值
arr[i] = i + 5;
printf("%d = %d\n", i, arr[i]); // 5-14
}
// 满初始化(注意C语言不进行越界检查)
// int arr3[3] = {1, 2, 3};
// 部分初始化后面默认0
// int arr[10] = {2,3,4,5};
// 只定义 不初始化
int arr5[10]; // 默认随机的数
int arr2[] = {2, 3, 4, -1, 23, 6};
int len2 = sizeof(arr2) / sizeof(arr2[0]);
for (int i = 0; i < len2; i++)
{
printf("%d", arr2[i]);
}
printf("\n");
int len8 = sizeof(arr8) / sizeof(arr8[0]);
for (int i = 0; i < len8; i++)
{
printf("%d", arr8[i]); // 0
}
return 0;
}
3. 数组在内存中
-
数组名是一个地址的常量,代表数组中首元素的地址
-
一维数组在内存中是一组连续的存储空间。
#include <stdio.h>
int main()
{
// 数据在内存中是一段连续的存储空间
// 查看数组的地址
// 整型数组
int arr[5] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);
printf("\n");
for (int i = 0; i < len; i++)
{
printf("%p\n", &arr[i]);
}
// 数组的地址 = 数组的首个元素的地址
// printf("arr = %p\n", &arr);
// printf("arr[0] = %p\n", &arr[0]);
return 0;
}
4. 数组的案例
4.1 一维数组的最值
#include <stdio.h>
int main()
{
int arr[] = {1, 2, 4, 34, 12, 88, -2};
int tempMax = arr[0];
int tempMin = arr[0];
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
if (arr[i] > tempMax)
{
tempMax = arr[i];
}
if (arr[i] < tempMin)
{
tempMin = arr[i];
}
}
printf("max = %d\n", tempMax);
printf("min = %d\n", tempMin);
return 0;
}
4.2 一维数组的逆置
#include <stdio.h>
int main()
{
char arr[] = {'a', 'b', 'c', 'd'};
// 数组的首元素下标
int i = 0;
int j = sizeof(arr) / sizeof(arr[0]) - 1;
int temp;
while (i < j)
{
// 元素交换
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
// 下标移动
i++;
j--;
}
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
printf("%c", arr[i]);
}
return 0;
}
4.3
5. 数组和指针
5.1 通过指针操作数组元素(重点)
-
数组名字是数组的首元素地址,但它是一个常量
-
* 和 [] 效果一样,都是操作指针所指向的内存
#include <stdio.h>
int main()
{
int arr[] = {1, 2, 3, 4, 44, 55, 13, 5};
printf(" arr = %p\n", &arr[0]);
int *p = arr;
printf("p = %p\n", p);
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
// printf("arr[%d] = %d", i, arr[i]);
printf("arr[%d] = %d\n", i, *(arr + i));
}
return 0;
}
1.数组名是一个常量,不允许重新赋值。
2.指针变量是一个变量,可以重新赋值。
3.p+i 和 array+i 均表示数组元素 array[i]的地址,均指向 array[i]
4.*(p+i)和*(array+i)均表示 p+i 和 array+i 所指对象的内容 array[i]。
5.*p++:等价于*(p++)。其作用:先得到*p,再使 p=p+1。
5.2 数组指针访问
#include <stdio.h>
int main()
{
int arr[] = {66, 2, 3, 4, 44, 55, 13, 5};
printf(" arr = %p\n", &arr[0]);
int *p = arr;
printf("p = %p\n", p);
// printf("%d\n", *(arr)); // 第一个值
// printf("%d\n", *(p)); // 第一个值
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
// arr + i 和 p + i 都是指向arr[i]的地址
// *(arr + i) 和 *(p + i) 都是指向arr[i]
// *(p++) == *p ++ 先获取*p, p = p + 1(步长)
// printf("arr[%d] = %d", i, arr[i]);
// printf("arr[%d] = %d\n", i, *(arr + i));
// printf("arrr[%d] = %d\n", i, *(p + i));
printf("arrr[%d] = %d\n", i, *p++);
}
return 0;
}
5.3 指针数组
-
指针数组,它是数组,数组的每个元素都是指针类型
#include <stdio.h>
int main()
{
// 指针数组, 是数组, 每个元素都是指针类型
int *arr[3];
int a = 10;
int b = 20;
int c = 30;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
// 数组的形式
// printf("%d\n", *(arr[i]));
// 指针的形式
// *(arr + i)是地址,再*(解引用操作符)就是值
// printf("%p\n", *(arr + i)); // 指针
printf("%d\n", *(*(arr + i)));
}
return 0;
}
5.4 数组名做函数参数
-
数组名做函数参数,函数的形参本质上就是指针
#include <stdio.h>
void show_arr(int *array, int length)
{
for (int i = 0; i < length; i++)
{
// printf("%d\n",array[i]);
// printf("%d\n", *array++);
printf("%d\n", *(array + i));
}
}
int main()
{
int arr[] = {2, 3, 4, 12, 34, 67, 45};
int len = sizeof(arr) / sizeof(arr[0]);
// 数组当成参数传递,可以使用指针的形式访问, 也可以使用原数组的方式访问
// 传递数组参数时,可以&arr,也可以直接arr
// 因为我们获取的数组地址,地址常量 = 地址首元素地址
// 打印数组
show_arr(arr, len);
return 0;
}
6. 字符数组与字符串
6.1 字符数组与字符串区别(重点)
-
C语言中没有字符串这种数据类型,可以通过char的数组来替代
-
数字0(和字符 '\0' 等价)结尾的char数组就是一个字符串,字符串是一种特殊的char的数组
-
如果char数组没有以数字0结尾,那么就不是一个字符串,只是普通字符数组
#include <stdio.h>
// C语言中没有字符串这种类型, 看到都是char类型的数组
// 字符串是一种特殊的char的数组
int main()
{
char arr[] = {'a', 'b', 'c', 'd', 'e', '\0'};
printf("%s\n", arr);
// int len = sizeof(arr) / sizeof(arr[0]);
// for (int i = 0; i < len; i++)
// {
// printf("%c\n",arr[i]);
// }
char arr2[] = "hello word";
printf("%s\n", arr2);
// \0之后的数据不可见, 表示结束
char arr3[] = "hello我 \0 word \0 123";
printf("%s\n", arr3);
return 0;
}
6.2 字符指针(重点)
-
字符指针可直接赋值为字符串,保存的实际上是字符串的首地址
-
这时候,字符串指针所指向的内存不能修改,指针变量本身可以修改
#include <stdio.h>
int main()
{
// 定义一个字符指针变量
// 保存的是字符串的首地址(常量)
// 把p当作一个变量就行
char *p = "Hello, World!";
// Bus error :10 内存指向未知空间 或者已经销毁的空间 或者越界
//*p = "aaabbb"; // 不可以改变,因为*p是一个地址常量
// char * p = const char * p
// 而p是指针变量
p = "aabbcc";
printf("%s\n", p);
return 0;
}
7. 字符的输入和输出
#include <stdio.h>
int main()
{
char str[6] = {};
// 不需要加 &,因为这是一个字符数组
// 直接使用scanf不安全,越界问题(就算超过6个也可以输出)
printf("请输入字符串: ");
// 1. scanf("%s", str);
// 2. gets也是不安全的
// gets(str);
// 3. fgets安全的,保障数据的准确性
// stdin标准输入流
// sizeof(str)判断的大小
// 如果输入超过6个字符,只会显示5个字符,最后一个是\0
fgets(str, sizeof(str), stdin);
printf("str = %s\n", str);
return 0;
}
8. 字符串常用库函数(string.h)
strlen(长度)
#include <stdio.h>
#include <string.h>
int main()
{
// char *p = "abc d";
char *p = "abc d\0";
// 获取字符串长度
// /0不算长度,/0后面的也不算长度
printf("%s\n", p);
int len = strlen(p);
printf("%d\n", len);
return 0;
}
strcpy(拷贝覆盖)
#include <stdio.h>
#include <string.h>
int main()
{
char src[10] = "hello";
char src2[10] = "world";
// 拷贝 覆盖原来内容
// 拷贝保留足够大的空间,否则溢出
strcpy(src2, src);
printf("%s\n", src2); //hello
return 0;
}
strcmp(比较)
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20] = "Worle";
char str2[100] = "World";
// 比较运算符:字符串中的字符逐个比较
// 按照ASCII码进行比较的结果
// 相等 0
// s1 > s2 大于0
// s1 < s2 小于0
if (strcmp(str1, str2) == 0)
{
printf("相等\n");
}
else if (strcmp(str1, str2) > 0)
{
printf("s1 > s2\n");
}
else
{
printf("s1 < s2\n");
}
return 0;
}
strcat(拼接)
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "hello";
char str2[] = "word";
// 将str1内容拼接到str2的内容
// 保证空间是足够的
strcat(str2, str1); // wordhello
printf("%s\n", str2);
return 0;
}
自实现 strlen
#include <stdio.h>
// 获取字符长度
// 字符数组形式/指针形式
int my_strlen(char *p)
{
// 初始变量接收长度
int len = 0;
// 判断字符已经到最后 \0
while (p[len] != '\0')
{
len++;
}
return len;
}
int main()
{
char *p = "hello";
printf("%d\n", my_strlen(p));
return 0;
}