首页 > 其他分享 >14. C语言 指针(深入理解)

14. C语言 指针(深入理解)

时间:2025-01-14 10:02:13浏览次数:3  
标签:14 int ip C语言 地址 数组 printf 指针

本章目录:


前言:

在 C 语言中,指针是一种存储变量地址的变量。它是理解计算机内存布局、动态内存分配和函数调用背后机制的重要工具。指针不仅能提高程序的灵活性,还能显著提升程序的性能。


什么是指针?

简单来说,指针就是一个变量,其值是另一个变量在内存中的地址。例如:

int a = 10; // 变量 a 的值为 10
int *p = &a; // 指针 p 存储的是变量 a 的地址

在这里:

  • int *p; 定义了一个整型指针变量 p
  • &a 获取变量 a 的内存地址。
  • p 存储的正是变量 a 的地址。

通过指针 p,我们可以访问 a 的值,使用解引用操作符 *

printf("Value of a: %d\n", *p); // 输出 a 的值

内存与地址:指针的基础

理解指针之前,先认识内存地址的意义:

  • 内存可以看作由一系列连续编号的单元组成。
  • 每个变量都存储在特定的内存单元中,& 操作符可获取变量的地址。

示例代码:

#include <stdio.h>

int main() {
    int var = 20;  // 定义一个整型变量
    int *ip;       // 定义一个整型指针
    ip = &var;     // 获取 var 的地址并赋值给 ip

    printf("Address of var: %p\n", &var);
    printf("Address stored in ip: %p\n", ip);
    printf("Value of *ip: %d\n", *ip);

    return 0;
}

运行结果:

Address of var: 0x7ffeeaae08d8
Address stored in ip: 0x7ffeeaae08d8
Value of *ip: 20

指针的声明与使用

指针变量的声明

指针变量需要声明其类型,以确保指针指向的内存区域正确解释其内容。语法如下:

type *var_name;

示例:

  • int *ip; —— 整型指针
  • float *fp; —— 浮点型指针
  • char *cp; —— 字符型指针

指针与地址的关系

在指针变量中存储地址后,可以通过 * 操作符解引用,访问地址对应的值:

int a = 100;
int *p = &a;
printf("Value of a: %d\n", *p); // 解引用获取 a 的值

注意:

  1. p 是一个指针,存储的是地址。
  2. *p 是指针指向地址中的值。

空指针与野指针

空指针(NULL Pointer)

空指针是一种特殊的指针,表示该指针不指向任何有效的内存地址。初始化指针为 NULL 是一种良好的编程习惯:

int *ptr = NULL;
if (ptr) {
    printf("Pointer is not NULL\n");
} else {
    printf("Pointer is NULL\n");
}
  • NULL 常用于检查指针是否被初始化或是否有效。
  • 在多数系统中,地址 0 是保留地址,不可访问。

野指针(Dangling Pointer)

未初始化的指针称为野指针。使用野指针可能导致程序行为未定义,因此,指针在创建后必须初始化:

int *p;      // 野指针
int a = 10;
p = &a;      // 初始化

指针进阶:从数组到函数

指针与数组

数组的名称是一个常量指针,指向数组的起始地址。通过指针可以遍历数组:

int arr[] = {1, 2, 3, 4};
int *p = arr;

for (int i = 0; i < 4; i++) {
    printf("Value at index %d: %d\n", i, *(p + i));
}

指针数组

指针数组是存储指针的数组。例如,一个存储字符串的数组可以定义为指针数组:

char *strings[] = {"Hello", "World", "C Language"};
for (int i = 0; i < 3; i++) {
    printf("%s\n", strings[i]);
}

指向指针的指针

C 语言允许使用多级指针。二级指针存储的是一级指针的地址:

int a = 10;
int *p = &a;
int **pp = &p;

printf("Value of a: %d\n", **pp);

函数指针

函数也有地址,可以通过函数指针调用函数:

#include <stdio.h>

void greet() {
    printf("Hello, World!\n");
}

int main() {
    void (*func_ptr)() = greet; // 定义一个函数指针
    func_ptr();                // 通过函数指针调用函数

    return 0;
}

指针的算术运算

指针支持基本算术运算,例如递增(++)、递减(--)和加减(+-)。运算基于指针的类型大小:

int arr[] = {10, 20, 30};
int *p = arr;

printf("First element: %d\n", *p);
p++; // 移动到下一个元素
printf("Second element: %d\n", *p);

常见错误与调试技巧

  1. 未初始化的指针:始终将指针初始化为 NULL 或有效地址。
  2. 访问释放的内存:避免使用已经 free 的指针。
  3. 指针越界:确保指针操作不超过分配的内存范围。

调试技巧

  • 使用调试器(如 gdb)检查指针的值和地址。
  • 打印指针的值及其解引用结果,快速定位问题。

总结

指针是 C 语言的核心,掌握指针可以帮助你更深入理解底层操作。通过指针可以高效管理内存、优化代码,并实现许多高级功能。

推荐练习:

  1. 定义一个指针,操作基本数据类型和数组。
  2. 实现一个简单的动态内存分配程序。
  3. 使用函数指针实现回调机制。

学习指针虽有挑战,但一旦掌握,你将在 C 编程中如鱼得水!


标签:14,int,ip,C语言,地址,数组,printf,指针
From: https://blog.csdn.net/wzt001005/article/details/144851994

相关文章

  • 15. C语言 函数指针与回调函数
    本章目录:前言什么是函数指针?定义声明方式函数指针的基本用法示例:最大值函数输出示例:回调函数与函数指针什么是回调函数?通俗解释示例:回调函数实现动态数组填充输出示例:进一步探索:带参回调函数输出示例:函数指针的进阶技巧函数指针数组返回函数指针的函数输出示例:......
  • 《ESP32-S3使用指南—IDF版 V1.6》第二章 常用的C语言知识点
    第二章常用的C语言知识点1)实验平台:正点原子DNESP32S3开发板2)章节摘自【正点原子】ESP32-S3使用指南—IDF版V1.63)购买链接:https://detail.tmall.com/item.htm?&id=7684993426594)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32S3.html......
  • C语言初阶习题(2分支语句和循环语句-for)【10】杨辉三角
    1.题目描述——在屏幕上打印杨辉三角。2.思路第一步先尝试打印下三角第二步,分析他们之间的关系3.代码实现#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>intmain(){ intn=0; scanf("%d",&n); intarr[100][100]={0}; inti=0; in......
  • C语言初阶习题【27】猜名次
    1.题目描述5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果:A选手说:B第二,我第三;B选手说:我第二,E第四;C选手说:我第一,D第二;D选手说:C最后,我第三;E选手说:我第四,A第一;比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。2.思路3.代码实现#include<stdio.h>in......
  • c语言——【linux】多线程编程 (内附练习及代码)
    1:开启一个线程主线程中:使用标准IO,向一个文件中写入任意数据分支线程:使用标准IO,读取该文件中的数据#include<stdio.h>#include<string.h>#include<unistd.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<p......
  • 高阶C语言|探索指针的根源之目(进阶指针)
    文章目录前言1.字符指针(`char*`)1.1字符串常量与指针1.2字符指针的使用2.数组指针与指针数组2.1指针数组2.2数组指针3.数组与指针传参3.1一维数组传参3.2二维数组传参4.函数指针(`functionpointer`)4.1函数指针的基本用法4.2使用函数指针数组5.指向函数指......
  • C语言-循环结构
    循环结构:重复执行代码1、for循环    循环用于在知道循环次数的情况下使用。三个部分:初始化、条件判断和更新    基本形式:                    嵌套循环:                2、while循环        循环在......
  • Wallpaper壁纸制作学习记录14
    交互式操控变形动画操控变形动画与ScenceScript结合使用还可用于创建交互式壁纸元素。在本次实例中,将讲解如何允许用户抓取和拖动单个骨骼。交互式骨骼这里提供了本次实例中的项目下载链接:果冻项目。设置操控变形动画为了实现这一点,需要将操控变形动画与SceneScript......
  • C语言:虚拟地址空间及编译模式
    所谓虚拟地址空间,就是程序可以使用的虚拟地址的有效范围。虚拟地址和物理地址的映射关系由操作系统决定,相应地,虚拟地址空间的大小也由操作系统决定,但还会受到编译模式的影响。这节我们先讲解CPU,再讲解编译模式,让大家了解编译器是如何配合CPU来提高程序运行速度的。CPU的......
  • C++:指针、类型指针与引用,一文全掌握!
    在C++语言中,指针类型、类型指针及引用是三个密切相关而又各有特点的概念。理解它们之间的区别和联系对于掌握C++的内存管理和编程技巧至关重要。本文将深入探讨这些概念,帮助读者更好地理解它们在C++中的使用和重要性。一、指针类型与类型指针的区别在C++中,指针类型的定义涉......