目录
char s[]="hello" 与 char *s="hello" 的区别
内存的基本概念
内存是计算机用于临时存储程序和数据的硬件,具有以下特点:
-
按字节编址:每个字节有唯一地址
-
随机访问:可按地址直接访问任意位置
-
易失性:断电后数据丢失
变量与地址
a是变量,&a是地址
int a = 10; // 在栈上分配4字节内存
// 查看变量地址
printf("a的地址: %p\n", &a); // 输出0x7ffc5a3b2a10
指针的本质
-
指针就是内存地址
-
指针变量,是用来存放内存地址的变量
指针的定义
类型 *指针变量名;



通过指针修改变量
指针的解引用

int *p 与 (*p)的区别
-
int *p- 指针声明 -
(*p)- 指针解引用

p一指针变量,它的内容是地址量
*p一指针的目标,它的内容是数据(a)
&p一指针变量占用的存储区域的地址,是个常量
int a = 4211;
int *p = &a;
printf("p = %p\n", p); // p的内容:a的地址
printf("*p = %d\n", *p); // *p的值:a的内容
printf("&p = %p\n", &p); // &p的值:p自身的地址
指针运算
指针运算是以指针所存放的地址作为运算量而进行的
指针运算的实质就是地址的计算
指针的算术运算
普通加减
#include <stdio.h>
int main()
{
int a = 4211;
int *p = &a;
(*p)++;
printf("a=%d,p=%p\n",a,p);
printf("&a=%p,&p=%p\n",&a,&p);
printf("&a+1=%p\n",&a+1);
printf("p+1=%p\n",p+1);
printf("&p+1=%p\n",&p+1);
return 0;
}
a=4212,p=0x7ffdb245383c
&a=0x7ffdb245383c,&p=0x7ffdb2453840
&a+1=0x7ffdb2453840
p+1=0x7ffdb2453840
&p+1=0x7ffdb2453848
观察规律:
#include <stdio.h>
int main()
{
int a[] = {4,2,1,1};
int *p=a;
printf("*p:%d, p:%p\n",*p,p);
printf("*(p+2):%d, p+2:%p\n",*(p+2),p+2);
printf("(*(p+2)-*(p+1)):%d, (p+2)-(p+1):%p,%d\n",(*(p+2)-*(p+1)),(p+2)-(p+1),(p+2)-(p+1));
return 0;
}
*p:4, p:0x7ffe32eaadf0
*(p+2):1, p+2:0x7ffe32eaadf8
(*(p+2)-*(p+1)):-1, (p+2)-(p+1):0x1,1
自增自减
运行*p++,(*p)++这两个的结果是否一样


第一行*p与p,写出了a的值和a的位置
第二行*p与p,写出了a的位置+4byte的值和a的位置+4byte
因为这个位置没有定义变量,所以值不确定
*p++,先改变位置,在进行解引用,解出了其他地址的值
第三行*v与v,写出了a的值+1和a的位置
(*v)++,先进行解引用,在改变变量的值
int *p和char *p有什么区别
1. 解引用后的类型
-
int *p:通过*p访问到的是一个int类型的值,通常占 4 个字节。 -
char *p:通过*p访问到的是一个char类型的值,占 1 个字节。
2. 指针算术运算的步长
指针进行 p++、p + n 等运算时,移动的字节数取决于指向类型的大小。
-
int *p:p++会向前移动sizeof(int)个字节(通常是 4)。 -
char *p:p++会向前移动sizeof(char)个字节(即 1)。
因此,用 int * 遍历数组时一次跳过一个整型元素,用 char * 则可以逐个字节遍历内存。
指针和数组
数组指针是指数组在内存中的起始地址
数组元素的地址是指数组元素在内存中的起始地



注意事项:
指针变量和数组名都是地址量
数组名与指针变量的深度对比
| 对比维度 | 数组名 (如 int arr[5]) | 指针变量 (如 int *p) |
|---|---|---|
| 本质 | 地址常量(符号常量) | 地址变量 |
| 内存占用 | 整个数组的大小 | 固定大小(4/8字节) |
| 可修改性 | 不可修改(常量) | 可修改 |
| 类型含义 | 代表整个数组结构 | 代表一个地址存储单元 |
| &操作 | 得到整个数组的地址(值相同,类型不同) | 得到指针变量自身的地址 |
| sizeof | 整个数组的大小 | 指针本身的大小 |
指针和二维数组
使用一级指针遍历二维数组


行指针
什么是行指针?
行指针也称为数组指针,是指向整个一维数组的指针,而不是指向单个元素。它存储的是整个一维数组的地址。
<数据类型>(*<指针变量名>)[表达式]; int a[3][4]; // 二维数组 int (*p)[4]; // 行指针,指向包含4个int的数组
二维数组名的本质
int a[3][4]; // a 的类型是 int (*)[4],即行指针类型 // a + 1 移动一行(4个int,16字节,假设int为4字节) // 注意:a 是常量指针,不能修改(如a++非法)方括号中的常量表达式表示指针加1,移动几个数据。
基本语法
// 语法:<数据类型> (*<指针变量名>)[列数];
int (*p)[4]; // 指向包含4个int的数组
float (*fp)[10]; // 指向包含10个float的数组
// 注意:括号是必须的,因为[]的优先级高于*
// 如果没有括号,int *p[4]; 则表示指针数组(一个数组,其元素为int指针)
初始化
int a[3][4];
int (*p)[4] = a; // 将二维数组名赋值给行指针,即指向第一行
// 也可以指向某一行
int (*p2)[4] = &a[1]; // 指向第二行(行索引从0开始)

用行指针遍历二维数组



字符指针与字符串
对字符串进行一个遍历,并大小写进行转换

![]()
当一个字符指针指向一个字符串常量时,不能修改指针指向的对象的值

char s[]="hello" 与 char *s="hello" 的区别
这两个声明看起来相似,但本质完全不同。以下是它们的详细对比:
| 特性 | char s[] = "hello"; | char *s = "hello"; |
|---|---|---|
| 类型 | 字符数组 | 字符指针 |
| 内存分配 | 在栈上分配数组空间 | 指针变量在栈上,指向字符串常量(存储在只读区域) |
| 存储位置 | 数组存储在栈/数据段(取决于声明位置) | 指针变量在栈上,字符串常量在只读数据段 |
| 可修改性 | 可以修改数组内容(如 s[0]='H') | 不可修改字符串内容(尝试修改会导致未定义行为) |
| sizeof() 结果 | 返回数组大小(6,包含'\0') | 返回指针大小(通常是 4 或 8 字节) |
| 赋值操作 | 不能对数组名整体赋值(s = "world" 错误) | 可以重新赋值指向其他字符串(s = "world" 正确) |
| 指针运算 | 数组 名不是左值,不能自增( | 指针可以自增(s++ 正确) |
| 内存管理 | 自动管理生命周期 | 需要确保指针指向有效的内存 |
| 作为函数参数 | 退化为指针,传递数组首地址 | 直接传递指针值 |
实现字符串的连接




&spm=1001.2101.3001.5002&articleId=157516140&d=1&t=3&u=f9eb41afc19a4568a31e87e8725c2c54)
220

被折叠的 条评论
为什么被折叠?



