当前位置:首页 > 科技  > 软件

深入 C++ 和 C 的指针世界

来源: 责编: 时间:2024-05-16 09:03:34 82观看
导读在C和C++编程中,指针是一个至关重要的概念。从初学者到高级开发者,掌握指针的使用不仅能提高代码效率,还能增强对内存管理的理解。一、初级:指针基础1.什么是指针?指针是一个变量,其值为另一个变量的地址。简单来说,指针存储

在C和C++编程中,指针是一个至关重要的概念。从初学者到高级开发者,掌握指针的使用不仅能提高代码效率,还能增强对内存管理的理解。2tv28资讯网——每日最新资讯28at.com

2tv28资讯网——每日最新资讯28at.com

一、初级:指针基础

1.什么是指针?

指针是一个变量,其值为另一个变量的地址。简单来说,指针存储的是内存地址而不是数据本身。2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int main() {  int a = 10;  int* p = &a; // p 是一个指向 a 的指针    printf("a 的值: %d/n", a); // 输出 10  printf("p 指向的地址: %p/n", p); // 输出 a 的地址  printf("*p 的值: %d/n", *p); // 输出 10 (解引用指针 p 获取值)    return 0;}

在上面的例子中,int* p 声明了一个指向整型变量的指针 p,并将 a 的地址赋给了它。*p 用于解引用指针,从而获得 a 的值。2tv28资讯网——每日最新资讯28at.com

2.指针的基本操作

  • 声明指针:int* p;
  • 获取变量地址:p = &a;
  • 解引用指针:*p

3.指针和数组

指针和数组密切相关。在很多情况下,指针可以用来遍历数组。2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int main() {int arr[] = {1, 2, 3, 4, 5};int* p = arr; // p 指向数组的第一个元素for (int i = 0; i < 5; i++) {printf("%d ", *(p + i)); // 使用指针遍历数组}return 0;}

4.指针数组 

数组中的元素是指针类型,可以用来存储一组指针。2tv28资讯网——每日最新资讯28at.com

int x = 10, y = 20, z = 30;int *ptrArr[3] = {&x, &y, &z};printf("Second element: %d/n", *ptrArr[1]); // 访问指针数组的第二个指针所指向的值

5.数组指针(pointer to an array) 

是一种指向数组的指针,它与指向数组第一个元素的普通指针不同。数组指针的主要用途是在处理多维数组时更加方便。这里详细介绍数组指针的定义和使用方法。2tv28资讯网——每日最新资讯28at.com

数组指针是指向数组的指针,其定义方式如下:2tv28资讯网——每日最新资讯28at.com

int (*ptr)[N]; 其中,N是数组的大小。ptr是一个指向包含N个整型元素的数组的指针。2tv28资讯网——每日最新资讯28at.com

数组指针的使用 以下是一些使用数组指针的示例:2tv28资讯网——每日最新资讯28at.com

(1) 一维数组指针2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int main() {    int arr[5] = {1, 2, 3, 4, 5};    int (*ptr)[5] = &arr; // ptr是指向包含5个整型元素的数组的指针    printf("First element: %d/n", (*ptr)[0]);    printf("Second element: %d/n", (*ptr)[1]);    return 0;}

在这个例子中,ptr指向数组arr,通过(*ptr)[i]访问数组中的元素。2tv28资讯网——每日最新资讯28at.com

(2) 二维数组指针 2tv28资讯网——每日最新资讯28at.com

对于二维数组,数组指针的使用更为常见和有用:2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int main() {    int arr[3][4] = {        {1, 2, 3, 4},        {5, 6, 7, 8},        {9, 10, 11, 12}    };    int (*ptr)[4] = arr; // ptr是指向包含4个整型元素的数组的指针    for (int i = 0; i < 3; ++i) {        for (int j = 0; j < 4; ++j) {            printf("%d ", ptr[i][j]);        }        printf("/n");    }    return 0;}

在这个例子中,ptr是一个指向包含4个整型元素的数组的指针,也就是指向二维数组的每一行。通过ptr[i][j]访问二维数组中的元素。2tv28资讯网——每日最新资讯28at.com

二、中级:指针进阶

1.指针的指针

指针不仅可以指向数据,还可以指向另一个指针,这种情况称为指针的指针。2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int main(){  int a = 10;  int* p = &a;  int** pp = &p; // pp 是一个指向指针 p 的指针    printf("a 的值: %d/n", a); // 输出 10  printf("*p 的值: %d/n", *p); // 输出 10  printf("**pp 的值: %d/n", **pp); // 输出 10    return 0;}

2.函数指针

函数指针是指向函数的指针,可以用来动态调用函数。2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int add(int a, int b) {return a + b;}int main() {int (*func_ptr)(int, int) = &add; // 声明一个指向函数的指针int result = func_ptr(3, 4); // 调用函数printf("结果: %d/n", result); // 输出 7return 0;}

3.指针函数 

是一个返回指针的函数。它与函数指针不同,函数指针是指向函数的指针,而指针函数是返回值为指针类型的函数。下面详细介绍指针函数的定义、使用方法及一些常见的例子。2tv28资讯网——每日最新资讯28at.com

定义指针函数,指针函数的定义方式是指定函数返回值为指针类型,例如:2tv28资讯网——每日最新资讯28at.com

int* func();

这表示func是一个返回int类型指针的函数。2tv28资讯网——每日最新资讯28at.com

指针函数的使用 指针函数通常用于动态分配内存、返回数组、字符串或结构体等情况。以下是一些使用指针函数的例子:2tv28资讯网——每日最新资讯28at.com

(1) 返回指向单个变量的指针2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int* getNumber() {    static int num = 42; // 使用static使num的生命周期延续到函数之外    return #}int main() {    int *ptr = getNumber();    printf("Number: %d/n", *ptr);    return 0;}

在这个例子中,getNumber函数返回指向num的指针。因为num是静态变量,它在函数返回后依然存在。2tv28资讯网——每日最新资讯28at.com

(2) 返回动态分配内存的指针2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>#include <stdlib.h>int* allocateArray(int size) {    int *arr = (int *)malloc(size * sizeof(int));    return arr;}int main() {    int *arr = allocateArray(5);    if (arr != NULL) {        for (int i = 0; i < 5; i++) {            arr[i] = i * 2;        }        for (int i = 0; i < 5; i++) {            printf("%d ", arr[i]);        }        printf("/n");        free(arr); // 别忘了释放内存    }    return 0;}

这个例子中,allocateArray函数返回一个指向动态分配内存的指针。2tv28资讯网——每日最新资讯28at.com

(3) 返回指向数组的指针2tv28资讯网——每日最新资讯28at.com

复制代码#include <stdio.h>int* getArray() {    static int arr[5] = {1, 2, 3, 4, 5};    return arr;}int main() {    int *ptr = getArray();    for (int i = 0; i < 5; i++) {        printf("%d ", ptr[i]);    }    printf("/n");    return 0;}

在这个例子中,getArray函数返回指向静态数组arr的指针。静态数组在函数返回后依然存在,所以返回的指针是有效的。2tv28资讯网——每日最新资讯28at.com

(4) 常见的应用场景 2tv28资讯网——每日最新资讯28at.com

  • 字符串操作:函数返回指向字符串的指针,例如处理输入输出字符串。
  • 链表操作:函数返回指向链表节点的指针,用于创建、插入、删除链表节点。
  • 动态内存管理:函数返回动态分配的内存指针,用于数组、结构体等的动态创建和管理。

4.动态内存分配

动态内存分配是指在运行时分配内存,而不是在编译时。C语言提供了 malloc、calloc 和 free 函数来进行动态内存分配和释放。2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>#include <stdlib.h>int main() {int* p = (int*)malloc(sizeof(int) * 5); // 分配5个整数大小的内存if (p == NULL) {printf("内存分配失败/n");return 1;}for (int i = 0; i < 5; i++) {p[i] = i + 1; // 使用分配的内存}for (int i = 0; i < 5; i++) {printf("%d ", p[i]);}free(p); // 释放内存return 0;}

常量指针和指针常量是两个非常重要的概念,在C和C++中经常被用到。它们分别表示指针和指针指向的内容的常量性不同。2tv28资讯网——每日最新资讯28at.com

5.常量指针(const pointer)

指针本身是常量,不能修改指向的地址,但可以修改指针指向的内容。2tv28资讯网——每日最新资讯28at.com

int x = 10;int y = 20;const int *ptr = &x; // 常量指针,指向一个整型常量*ptr = 5; // 错误,不能通过常量指针修改指向的内容ptr = &y; // 正确,可以修改常量指针指向的地址

6.指针常量(pointer to const)

指针指向的内容是常量,不能通过指针修改其指向的内容,但可以修改指针指向的地址。2tv28资讯网——每日最新资讯28at.com

int x = 10;int y = 20;int *const ptr = &x; // 指针常量,指针本身是常量,指向一个整型变量*ptr = 5; // 正确,可以通过指针修改指向的内容ptr = &y; // 错误,不能修改指针常量指向的地址

总的来说,常量指针用于保护指向的内容不被修改,而指针常量用于保护指针本身不被修改。在实际编程中,根据需求选择合适的类型可以增强代码的安全性和可读性。2tv28资讯网——每日最新资讯28at.com

7.常量指针常量(const pointer to const)

是指指针本身和指针指向的内容都是常量,即既不能通过指针修改指向的地址,也不能通过指针修改指向的内容。2tv28资讯网——每日最新资讯28at.com

int x = 10;const int y = 20;const int *const ptr = &x; // 常量指针常量,指针和指向的内容都是常量*ptr = 5; // 错误,不能通过指针修改指向的内容ptr = &y; // 错误,不能修改指针指向的地址

在上面的例子中,ptr是一个指向整型常量的常量指针常量,因此既不能通过ptr修改指向的内容,也不能修改ptr指向的地址。这种类型的指针通常用于指向常量数据,以确保数据的不可变性。2tv28资讯网——每日最新资讯28at.com

三、高级:指针高级用法

1.指向函数的指针数组 

指针数组可以用来存储多个函数指针,从而实现动态调用不同的函数。2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>int add(int a, int b) {return a + b;}int subtract(int a, int b) {return a - b;}int multiply(int a, int b) {return a * b;}int main() {int (*func_ptr[])(int, int) = {add, subtract, multiply};int x = 10, y = 5;for (int i = 0; i < 3; i++) {printf("结果: %d/n", func_ptr[i](x, y));}return 0;}

2.指针与数据结构* 

在数据结构中,指针用于实现链表、树等结构。以下是单链表的简单实现:2tv28资讯网——每日最新资讯28at.com

#include <stdio.h>#include <stdlib.h>struct Node {int data;struct Node* next;};void printList(struct Node* n) {while (n != NULL) {printf("%d ", n->data);n = n->next;}}int main() {struct Node* head = NULL;struct Node* second = NULL;struct Node* third = NULL;head = (struct Node*)malloc(sizeof(struct Node));second = (struct Node*)malloc(sizeof(struct Node));third = (struct Node*)malloc(sizeof(struct Node));head->data = 1;head->next = second;second->data = 2;second->next = third;third->data = 3;third->next = NULL;printList(head);free(head);free(second);free(third);return 0;}

3.多维数组与指针

多维数组可以使用指针进行遍历和操作。2tv28资讯网——每日最新资讯28at.com

int main() {int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};int (*p)[3] = arr; // 指向包含3个整数的一维数组的指针for (int i = 0; i < 2; i++) {  for (int j = 0; j < 3; j++)   {    printf("%d ", p[i][j]);  }  printf("/n");}return 0;}

4.指针的陷阱与安全

指针的使用虽然强大,但也伴随着潜在的风险,如悬空指针、野指针、缓冲区溢出等。 2tv28资讯网——每日最新资讯28at.com

  • 悬空指针:指针指向的内存已经被释放,但指针本身未被重置为NULL。 
  • 野指针:指针未初始化或指向未分配的内存区域。
#include <stdio.h>#include <stdlib.h>int main() {int* p = (int*)malloc(sizeof(int));*p = 10;free(p);p = NULL; // 避免悬空指针if (p != NULL) {*p = 20; // 避免野指针} else {printf("指针已被释放/n");}return 0;}

5.C++中的智能指针 

C++11引入了智能指针,用于自动管理内存,避免内存泄漏。常见的智能指针包括 std::unique_ptr 和 std::shared_ptr。2tv28资讯网——每日最新资讯28at.com

#include <iostream>#include <memory>class Test {public:Test() { std::cout << "构造函数/n"; }~Test() { std::cout << "析构函数/n"; }};int main() {std::unique_ptr<Test> ptr1(new Test());std::shared_ptr<Test> ptr2 = std::make_shared<Test>();{std::shared_ptr<Test> ptr3 = ptr2;std::cout << "共享计数: " << ptr2.use_count() << std::endl;}std::cout << "共享计数: " << ptr2.use_count() << std::endl;return 0;}

6.指针的最佳实践 

  • 初始化指针:声明指针时尽量初始化。
  • 使用智能指针:在C++中尽量使用智能指针管理动态内存。 
  • 避免悬空指针和野指针:释放内存后将指针置为NULL,使用指针前确保其指向有效内存。 
  • 定期检查内存泄漏:使用工具如Valgrind进行内存检查。

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-88323-0.html深入 C++ 和 C 的指针世界

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 解锁 Python 超能力:十大变革性库与框架

下一篇: 八个将网页转为桌面应用程序的开源方案

标签:
  • 热门焦点
  • K60至尊版刚预热 一加Ace2 Pro正面硬刚

    K60至尊版刚预热 一加Ace2 Pro正面硬刚

    Redmi这边刚如火如荼的宣传了K60 Ultra的各种技术和硬件配置,作为竞品的一加也坐不住了。一加中国区总裁李杰发布了两条微博,表示在自家的一加Ace2上早就已经采用了和PixelWo
  • 消息称迪士尼要拍真人版《魔发奇缘》:女主可能也找黑人演员

    消息称迪士尼要拍真人版《魔发奇缘》:女主可能也找黑人演员

    8月5日消息,迪士尼确实有点忙,忙着将不少动画改成真人版,继《美人鱼》后,真人版《白雪公主》、《魔发奇缘》也在路上了。据外媒消息称,迪士尼将打造真人版
  • 线程通讯的三种方法!通俗易懂

    线程通讯的三种方法!通俗易懂

    线程通信是指多个线程之间通过某种机制进行协调和交互,例如,线程等待和通知机制就是线程通讯的主要手段之一。 在 Java 中,线程等待和通知的实现手段有以下几种方式:Object 类下
  • Automa-通过连接块来自动化你的浏览器

    Automa-通过连接块来自动化你的浏览器

    1、前言通过浏览器插件可实现自动化脚本的录制与编写,具有代表性的工具就是:Selenium IDE、Katalon Recorder,对于简单的业务来说可快速实现自动化的上手工作。Selenium IDEKat
  • 三万字盘点 Spring 九大核心基础功能

    三万字盘点 Spring 九大核心基础功能

    大家好,我是三友~~今天来跟大家聊一聊Spring的9大核心基础功能。话不多说,先上目录:图片友情提示,本文过长,建议收藏,嘿嘿嘿!一、资源管理资源管理是Spring的一个核心的基础功能,不
  • 使用Webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题

    使用Webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题

    1、前言在我们使用 Selenium 进行 UI 自动化测试时,常常会因为浏览器驱动与浏览器版本不匹配,而导致自动化测试无法执行,需要手动去下载对应的驱动版本,并替换原有的驱动,可能还
  • 从零到英雄:高并发与性能优化的神奇之旅

    从零到英雄:高并发与性能优化的神奇之旅

    作者 | 波哥审校 | 重楼作为公司的架构师或者程序员,你是否曾经为公司的系统在面对高并发和性能瓶颈时感到手足无措或者焦头烂额呢?笔者在出道那会为此是吃尽了苦头的,不过也得
  • 零售大模型“干中学”,攀爬数字化珠峰

    零售大模型“干中学”,攀爬数字化珠峰

    文/侯煜编辑/cc来源/华尔街科技眼对于绝大多数登山爱好者而言,攀爬珠穆朗玛峰可谓终极目标。攀登珠峰的商业路线有两条,一是尼泊尔境内的南坡路线,一是中国境内的北坡路线。相
  • OPPO K11搭载长寿版100W超级闪充:26分钟充满100%

    OPPO K11搭载长寿版100W超级闪充:26分钟充满100%

    据此前官方宣布,OPPO将于7月25日也就是今天下午14:30举办新品发布会,届时全新的OPPO K11将正式与大家见面,将主打旗舰影像,和同档位竞品相比,其最大的卖
Top
Baidu
map