目 录CONTENT

文章目录
C

C-指针(一)

~梓
2025-05-31 / 0 评论 / 0 点赞 / 5 阅读 / 0 字
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

一、指针案例

案例一

#include <stdio.h>

int main() {
    // a是整形变量
    int a = 10;

    // 声明一个指向整型的指针pa,把变量a的地址赋予它
    int* pa = &a;

    // 输出指针存储的地址值
    printf("%p", pa);
    return 0;

}

  1. 声明并初始化变量:创建一个整型变量 a,并初始化为 10。
  2. 声明并初始化指针:创建一个指向整型的指针 pa,并将变量 a的内存地址赋给它。
  3. 输出指针值:使用 printf函数和 %p格式说明符,以十六进制形式输出指针 pa存储的地址值。

案例二:

代码声明了四种不同数据类型的指针(char*short*int*double*),并通过 sizeof操作符分别计算它们的大小。在大多数系统中,所有指针类型占用的内存空间是相同的,因为它们存储的是内存地址,而地址的位数取决于系统架构(32 位或 64 位)。

#include <stdio.h>

int main() {
	char* pc = NULL;
	short* ps = NULL;
	int* pi = NULL;
	double* pd = NULL;

	// sizeof 返回的值的类型是无符号类型,也就是 unsigned int 
	printf("%d\n",sizeof(pc));
	printf("%d\n",sizeof(ps));
	printf("%d\n",sizeof(pi));
	printf("%d\n",sizeof(pd));

}

  1. 指针大小与类型无关
    无论指针指向何种数据类型(charshortintdouble等),其占用的内存空间只取决于系统架构。
    • 32 位系统:地址总线为 32 位,指针占用 4 字节(32 位)。
    • 64 位系统:地址总线为 64 位,指针占用 8 字节(64 位)。
  2. sizeof的返回值类型
    sizeof返回的是 size_t类型,它是无符号整数类型(通常定义在 <stddef.h>中)。在 64 位系统中,size_t可能是 unsigned longunsigned long long,因此使用 %d(有符号整数)打印可能会导致输出异常。建议使用 %zu来正确打印 size_t类型的值:
printf("%zu\n", sizeof(pc));  // 使用%zu格式说明符
  1. 空指针(NULL)的大小
    所有类型的空指针(如 NULL)在内存中占用的空间与普通指针相同,因为 NULL本质上是一个特殊的地址值(通常为 0)。

二、指针类型的定义

指针就是内存地址,我们所说的指针变量也就是存放内存地址的变量,变量有int,float等等类型,那我们的指针变量也需要不同的类型来存放内存地址变量。

#include <stdio.h>

int main() {
    int a = 0x11223344;
    int* pa = &a;
  
    // 打印指针pa的值,即变量 a 的地址。 
    printf("%p\n", pa);
  
    // 打印变量 a 的当前值(以十六进制形式显示)。
    printf("修改前a的值(十六进制): 0x%x\n", a);
  
    // 通过指针 pa 修改变量 a 的值。
	// *pa 表示通过指针 pa 解引用,即访问 pa 所指向的变量(这里是 a),并将其值设置为 0。
    *pa = 0;
    printf("修改后a的值(十六进制): 0x%x\n", a);
  
    return 0; 
}

C 语言中指针的基本使用

#include <stdio.h>

int main() {
    // 定义一个int类型的变量,值为42
    int num = 42;

    // 定义一个int类型的指针变量,并初始化为变量num的地址
    int* ptr = #

    // 输出指针ptr中存储的值(即ptr所指向的地址,也就是num的地址)
    printf("指针ptr中存储的地址: %p\n", ptr);

    // 直接输出变量num的地址(与ptr中存储的地址相同)
    printf("变量num的地址: %p\n", &num);

    // 对指针ptr进行解引用操作,输出ptr所指向的内存位置存储的值(即num的值)
    printf("ptr所指向的值: %d\n", *ptr);

    return 0;
}

printf语句输出内容解释:

  1. printf("指针ptr的地址: %p\n", ptr);
    • 输出的是指针 ptr中存储的地址值,即变量 num的地址(例如:0x7ffd8a3c6a5c)。
  2. printf("变量num的地址: %p\n", &num);
    • 输出的是变量 num本身的地址,与 ptr中存储的地址完全相同(例如:0x7ffd8a3c6a5c)。
  3. printf("ptr所指向的值: %d\n", *ptr);
    • 输出的是指针 ptr所指向的内存位置存储的值,即 num的值 42

关键概念总结:

  • 指针变量 ptr:存储的是变量 num的地址。
  • &num:取变量 num的地址。
  • *ptr:对指针 ptr进行解引用,访问其指向的内存位置存储的值。

更多情况展示

#include <stdio.h>

int main() {
    int num = 42;
    int* ptr = #

    printf("错误(未定义行为): %p\n", *ptr);     // 错误示例
    printf("ptr存储的地址: %p\n", ptr);      // 正确:ptr的值
    printf("num的地址: %p\n", &num);         // 正确:&num的值
    printf("ptr和&num是否相同: %d\n", ptr == &num);  // 输出1(真)
    printf("ptr自己的地址: %p\n", &ptr);     // ptr变量本身的地址
    printf("ptr指向的值: %d\n", *ptr);               // 42

    return 0;
}

输出

错误(未定义行为): 000000000000002A
ptr存储的地址: 000000000062FE1C
num的地址: 000000000062FE1C
ptr和&num是否相同: 1
ptr自己的地址: 000000000062FE10
ptr指向的值: 42

总结

  • 使用 %p:必须传递指针(地址),而不是整数。
  • 区分:
    • ptr(地址值) vs *ptr(地址指向的值)。
    • ptrnum 的地址) vs &ptr(指针自己的地址)。

扩充

在 C 语言中,指针必须存储内存地址,而不是普通整数值。

int num = 42;
int* s = num;  // 错误!

正确写法

如果想让指针 s 指向 num,必须用 & 取地址符

int num = 42;
int* s = #  // 正确!s存储num的地址

三、直接访问内存实例

以下是一个在 C 语言中直接访问内存地址的示例。需要注意,这种操作非常危险,可能导致程序崩溃或安全漏洞

#include <stdio.h>

int main() {
    int num = 42;  // 定义一个变量,存储在某个内存地址中

    // 获取变量num的地址
    int* ptr = #
    printf("num的地址: %p\n", (void*)ptr);

    // 通过指针直接修改内存中的值
    *ptr = 99;
    printf("修改后num的值: %d\n", num);  // 输出: 99

    // 定义一个新的指针,指向固定地址(仅作示例,不要在实际代码中这样做)
    // 注意:这个地址可能不存在或不可写,会导致段错误!
    int* dangerous_ptr = (int*)0x12345678;  // 假设的固定地址
    // *dangerous_ptr = 100;  // 危险操作!可能导致程序崩溃

    return 0;
}

四、解引用操作符

在 C 语言中,* 是解引用操作符,用于访问指针所指向的内存地址中的值。

一、何时需要使用 \* 打印值?

当你需要访问指针指向的变量的值时,使用 *

int num = 42;
int* ptr = #  // ptr存储num的地址

printf("%d\n", *ptr);  // 输出:42(访问ptr指向的值)

示例 2:通过指针修改值后打印

int num = 42;
int* ptr = #
*ptr = 99;  // 修改ptr指向的值(即num的值)

printf("%d\n", *ptr);  // 输出:99
printf("%d\n", num);   // 输出:99(num已被修改)

二、何时不使用 \*

当你需要打印指针本身存储的地址值时,直接使用指针变量名(无需 *)。

示例 3:打印指针存储的地址

int num = 42;
int* ptr = #

printf("%p\n", ptr);     // 输出:num的地址(如0x7ffe536b8aec)
printf("%p\n", &num);    // 同上:直接取num的地址

三、常见混淆场景

1. 指针变量 vs 指针指向的值

int num = 42;
int* ptr = #

// 混淆点:区分以下两个操作
printf("%p\n", ptr);   // 打印ptr存储的地址(0x7ffe...)
printf("%d\n", *ptr);  // 打印ptr指向的值(42)

2. 多级指针(如 int\**

int num = 42;
int* ptr = #
int** pptr = &ptr;  // 二级指针,存储ptr的地址

printf("%p\n", pptr);    // 输出:ptr的地址
printf("%p\n", *pptr);   // 输出:num的地址(即ptr的值)
printf("%d\n", **pptr);  // 输出:42(先解引用得到ptr,再解引用得到num)

四、判断口诀

  1. 看需求
    • 若需访问指针指向的值 → 使用 *
    • 若需查看指针存储的地址 → 直接用指针变量名。
  2. 结合 %p%d
    • %p(打印地址) → 直接用指针(如 ptr&num)。
    • %d(打印整数) → 用解引用(如 *ptr)。

五、示例

#include <stdio.h>

int main() {
    int num = 42;
    int* ptr = #

    printf("num的值: %d\n", num);        // 42
    printf("ptr指向的值: %d\n", *ptr);    // 42
    printf("ptr存储的地址: %p\n", ptr);  // 0x7ffe...
    printf("ptr自己的地址: %p\n", &ptr); // 另一个地址

    return 0;
}

六、注意事项

空指针解引用

int* ptr = NULL;
printf("%d\n", *ptr);  // 错误!解引用空指针会导致崩溃

未初始化的指针

int* ptr;  // 未初始化,可能指向随机地址
*ptr = 10; // 危险!可能覆盖重要内存

数组名作为指针

int arr[3] = {1, 2, 3};
printf("%d\n", *arr);  // 输出:1(数组名隐式转换为指向首元素的指针)
0

评论区