一、字符数组:字符串的存储容器
字符数组是用来存储字符串数据的重要数据结构。
基本定义与初始化
c
#include <stdio.h>
int main() {
// 方式1:逐个字符初始化
char ch[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
// 方式2:字符串直接初始化
char str[] = "Hello";
printf("ch: %s\n", ch);
printf("str: %s\n", str);
return 0;
}
内存布局
| | |
|------|-------|-------|-------|-------|-------|
| 字符数组 | H | e | l | l | o |
| 索引 | [0] | [1] | [2] | [3] | [4] |
自动大小计算
c
#include <stdio.h>
int main() {
char name[] = "张三"; // 编译器自动计算大小(包含\0)
char city[20] = "北京";
printf("姓名: %s\n", name);
printf("城市: %s\n", city);
printf("欢迎%s来到%s!\n", name, city);
// 查看数组大小
printf("name数组大小: %zu\n", sizeof(name));
printf("city数组大小: %zu\n", sizeof(city));
return 0;
}
输出结果:
makefile
姓名: 张三
城市: 北京
欢迎张三来到北京!
name数组大小: 7
city数组大小: 20
二、字符串的整行输入输出
问题:scanf遇到空格就停止
c
#include <stdio.h>
int main() {
char text[50];
printf("请输入带空格的文本: ");
scanf("%s", text); // 遇到空格就停止
printf("输出结果: %s\n", text); // 只会输出空格前的部分
return 0;//如输入abc defg只会输出abc要注意
}
解决方案:使用 %[^\n]
c
#include <stdio.h>
int main() {
char sentence[100];
printf("请输入一句话: ");
scanf("%[^\n]", sentence); // 读取直到换行符
printf("你输入的是: %s\n", sentence);
return 0;
}
三、指针:直接内存访问的利器
指针的重要性
- 直接内存访问能力
- 高效的数据操作
- 动态内存管理
- 复杂数据结构的实现
- 系统级编程支持
指针基础
c
#include <stdio.h>
int main() {
int a = 10; // 开辟一块内存空间
int *p = &a; // 使用&取变量a的地址
printf("变量a的值: %d\n", a);
printf("变量a的地址: %p\n", &a);
printf("指针p的值(存储的地址): %p\n", p);
printf("通过指针p访问的值: %d\n", *p);
return 0;
}
四、指针的解引用
指针的解引用(Dereferencing)是使用指针访问或修改其所指向内存中数据的操作。解引用操作使用 * 运算符。
c
#include <stdio.h>
int main() {
int num = 42;
int *ptr = # // ptr指向num
// 解引用:通过指针访问指向的值
printf("num的值: %d\n", num);
printf("通过指针访问的值: %d\n", *ptr); // 解引用
// 通过指针修改值
*ptr = 100; // 解引用并赋值
printf("修改后num的值: %d\n", num);
// 验证修改
printf("再次通过指针访问: %d\n", *ptr);
return 0;
}
五、指针的算术运算
指针的算术运算是C语言中一个强大但需要谨慎使用的特性。与普通算术运算不同,指针运算的结果取决于指针所指向的数据类型。
基本指针运算
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr; // 指向数组第一个元素
printf("初始位置:\n");
printf("ptr = %p, *ptr = %d\n", ptr, *ptr);
// 指针加法
ptr = ptr + 1; // 移动到下一个int元素
printf("ptr + 1:\n");
printf("ptr = %p, *ptr = %d\n", ptr, *ptr);
ptr = ptr + 2; // 再向后移动两个int元素
printf("ptr + 2:\n");
printf("ptr = %p, *ptr = %d\n", ptr, *ptr);
// 指针减法
ptr = ptr - 1; // 向前移动一个int元素
printf("ptr - 1:\n");
printf("ptr = %p, *ptr = %d\n", ptr, *ptr);
return 0;
}
六、*p++ 和 (*p)++ 的区别
*p++ - 指针移动
- 先计算
*p(获取当前指针指向的值) - 然后执行
p++(指针向后移动一个元素位置) - 返回之前获取的值
c
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40};
int *p = arr;
printf("*p++ = %d\n", *p++); // 输出:10
printf("当前 *p = %d\n", *p); // 输出:20(指针已移动)
printf("arr[0] = %d\n", arr[0]); // 输出:10(原值未变)
return 0;
}
(*p)++ - 值修改
- 先计算
*p(获取指针指向的值) - 然后对该值执行
++(将指针指向的内存位置的值加1) - 返回之前获取的值
- 指针位置不变
c
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40};
int *p = arr;
printf("(*p)++ = %d\n", (*p)++); // 输出:10
printf("当前 *p = %d\n", *p); // 输出:11(值已改变)
printf("arr[0] = %d\n", arr[0]); // 输出:11(原数组被修改)
return 0;
}
使用场景:
*p++- 关注指针移动(常用于遍历数组)(*p)++- 关注值的修改(修改指针指向的内容)