// 方式1:声明时初始化所有元素
int arr1[5] = {0, 1, 2, 3, 4};
// 方式2:部分初始化(剩余元素自动补0)
int arr2[5] = {10, 20}; // → [10, 20, 0, 0, 0]
// 方式3:自动推断长度
int arr3[] = {2,4,6}; // 长度=3
C
地址 | 值
0x1000 | arr[0] → 0
0x1004 | arr[1] → 1
0x1008 | arr[2] → 2
0x100C | arr[3] → 3
0x1010 | arr[4] → 4
Less
特性:
arr
是首元素地址的常量指针int len = sizeof(arr) / sizeof(arr[0]);
C
注意:
for(int i=0; i<5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
arr[2] = 100; // 直接通过索引修改
C
注意:索引从 0
开始,最大有效索引为 长度-1
int max = arr[0];
for(int i=1; i<5; i++){
if(arr[i] > max) {
max = arr[i];
}
}
C
int arr[5] = {0};
arr[5] = 10; // ❌ 访问越界 → 段错误或数据污染
printf("%p == %p", arr, &arr[0]); // 输出相同地址
// arr = &other; ❌ 数组名是常量指针,不可修改
int a[5], b[5] = {1,2,3,4,5};
a = b; // ❌ 错误!
memcpy(a, b, sizeof(b)); // ✅ 正确做法
C
C
#include
int main() {
int fib[20] = {0, 1}; // 初始化前两项
// 生成数列
for(int i=2; i<20; i++) {
fib[i] = fib[i-1] + fib[i-2];
}
// 打印输出
printf("斐波那契数列前20项:\n");
for(int i=0; i<20; i++){
printf("%d ", fib[i]);
if((i+1)%5 == 0) printf("\n"); // 每行5个
}
return 0;
}
C
输出效果:
0 1 1 2 3 5 8 13 21 34
55 89 144 233 377
610 987 1597 2584 4181
YAML
错误类型 | 错误示例 | 解决方案 |
---|---|---|
越界访问 | arr[5] = 10; |
检查循环条件i < 长度 |
未初始化访问 | int arr[5]; printf("%d", arr[0]); |
显式初始化数组 |
错误计算长度 | sizeof(arr) 在函数参数中使用 |
传递长度参数 |
1. 数组是连续内存块,索引从0开始
2. sizeof(arr) 仅在定义域有效
3. 数组名是常量指针(不可修改)
4. 越界访问会导致未定义行为
5. 数组间赋值需用memcpy或循环
Markdown
// 方式1:按行优先初始化
int matrix1[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 方式2:连续初始化(自动填充)
int matrix2[][4] = {1,2,3,4,5,6}; // → 2行4列,剩余补0
// 方式3:动态初始化
int* matrix3[3]; // 指针数组
for(int i=0; i<3; i++){
matrix3[i] = (int*)malloc(4 * sizeof(int));
}
C
地址 | 值
0x1000 | matrix[0][0] → 1
0x1004 | matrix[0][1] → 2
0x1008 | matrix[0][2] → 3
0x100C | matrix[0][3] → 4
0x1010 | matrix[1][0] → 5
...
Less
int* base = &matrix[0][0];
int row = 1, col = 2;
int* elem = base + (row * 4 + col); // 4为列数
C
固定列数传递(推荐)
void printMatrix(int mat[][4], int rows) {
for(int i=0; i
C
指针形式传递
void processMatrix(int* mat, int rows, int cols) {
for(int i=0; i
C
错误用法 | 问题分析 | 解决方案 |
---|---|---|
void func(int** mat) |
类型不匹配(静态数组) | 使用固定列数或一维指针 |
不指定列数:int mat[][] |
编译器无法计算地址 | 必须明确指定列数 |
动态数组传参未传递行列数 | 无法确定维度 | 显式传递行数和列数 |
段错误
int mat[3][4];
mat[3][0] = 5; // ❌ 行越界
错误传递动态数组
int** mat = malloc(3*sizeof(int*));
// 错误调用
printMatrix(mat, 3); // ❌ mat类型不匹配
C
忽略列数约束
void func(int mat[][]); // ❌ 未指定列数
C
1. 二维数组内存按行连续存储
2. 函数传参必须指定列数(动态数组除外)
3. 地址计算:base + (i*col + j)*sizeof(type)
4. 动态二维数组需传递行列数
5. GDB使用 x/[数量][格式] 命令查看内存
Markdown
char str1[] = {'H','e','l','l','o','\0'}; // 显式包含\0
char str2[] = "World"; // 隐式包含\0
内存布局:
地址 | 值
0x1000| 'H'
0x1001| 'e'
...
0x1005| '\0'
函数 | 风险点 | 安全替代方案 |
---|---|---|
scanf |
缓冲区溢出 | scanf("%10s", str) |
gets |
无长度限制 | fgets(str, size, stdin) |
函数 | 功能描述 | 安全替代方案 | 示例 |
---|---|---|---|
strlen |
计算字符串长度(不含\0) | strnlen (C11) |
strlen("Hello") → 5 |
strcpy |
字符串拷贝 | strncpy |
strcpy(dest, src) |
strcat |
字符串拼接 | strncat |
strcat(str, "!") |
strcmp |
字符串比较 | strncmp |
strcmp("a", "b") → 负数 |
strchr |
查找字符首次出现位置 | — | strchr("abc", 'b') → "bc" |
strstr |
查找子串首次出现位置 | — | strstr("hello", "ll") → "llo" |
strtok |
分割字符串 | strtok_r (线程安全) |
strtok(str, ",") |
strdup |
字符串动态复制(需free) | — | char* copy = strdup(str) |
// 安全拷贝(自动添加\0)
strncpy(dest, src, sizeof(dest)-1);
dest[sizeof(dest)-1] = '\0';
// 安全输入
fgets(str, sizeof(str), stdin);
str[strcspn(str, "\n")] = '\0'; // 去除换行符
char buffer[10];
scanf("%s", buffer); // 输入超10字符则溢出
攻击原理:
边界检查:
strncpy(dest, src, dest_size-1);
使用安全函数:
#define _CRT_SECURE_NO_WARNINGS // Windows需定义
gets_s(buffer, sizeof(buffer)); // C11安全函数
#include
#define MAX_stu 20
// 单个学生
typedef struct
{
char name[128]; // 姓名
char sex[5]; // 性别
short id; // 学号
int age; // 年龄
int sco; // 成绩
}stu_data;
// 一个班
typedef struct
{
stu_data data[MAX_stu]; // 学生 20 代表 20 个座位
int len; // 记录学生人数
}stu_class;
// 1、插入到那个班
// 2、插入什么数据
// 3、插入到哪里
/************************* 增 *************************/
/*
对 class 结构体中进行尾部数据的插入
函数 void pos_ins_list( stu_class * class , int pos);
参数
@ class 要操作的班级
返回值
无返回值
*/
void tail_ins_list( stu_class * class );
/************************* 删 *************************/
void tail_del_list( stu_class * class );
/************************* 改 *************************/
void chan_list( stu_class * class );
/************************* 查 *************************/
void find_list( stu_class * class );
/************************* 排序 *************************/
void sort_list( stu_class * class );
/************************* 打印 *************************/
void printf_Sql_List( stu_class * class );
// 如果你现在没听懂 一定是老师的问题 不是你的问题
// 我不喜欢 pua 自己的人
int main(int argc, char const *argv[])
{
/* 初始化结构体 */
// 创建一个 班级结构体
stu_class stu = {
// 学生数据初始化
.data = {
{"石昊" , "男" , 1 , 18 , 60},
{"萧炎" , "男" , 2 , 18 , 61},
{"牧尘" , "男" , 3 , 18 , 62},
{"林动" , "男" , 4 , 18 , 63},
{"韩立" , "男" , 5 , 18 , 64},
},
// 学生个数变量初始化
.len = 5
};
printf_Sql_List(&stu);
// 插入数据
tail_ins_list(&stu);
tail_ins_list(&stu);
printf_Sql_List(&stu);
return 0;
}
/************************* 增 *************************/
void tail_ins_list( stu_class * class )
{
// 判定是否为空指针
if (NULL == class)
{
puts("你没有传入班级");
return ;
}
// 判断满
if( MAX_stu < class->len)
{
puts("满了 塞钱都没用(ps:除非给系统的开发者(小声bb))");
return ;
}
// 输入数据
stu_data data;
printf("请输入学生数据:");
printf("姓名");
scanf("%s" , data.name );
printf("性别");
scanf("%s" , data.sex );
printf("学号");
scanf("%hd" , &data.id );
printf("年龄");
scanf("%d" , &data.age );
printf("成绩");
scanf("%d" , &data.sco );
// 插入数据
class->data[class->len] = data;
// 迭代长度
class->len++;
}
/************************* 打印 *************************/
void printf_Sql_List( stu_class * class )
{
// 循环
for (size_t i = 0; i < class->len ; i++)
{
// 打印数据
printf("name = %s sex = %s id = %d sco = %d age = %d \n" , \
class->data[i].name , class->data[i].sex , class->data[i].id \
, class->data[i].age , class->data[i].sco \
);
}
}