继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

C++指针资料详解与实例教程

函数式编程
关注TA
已关注
手记 219
粉丝 14
获赞 30

本文详细介绍了C++指针的基本概念和使用方法,包括指针的声明、使用、指针与内存地址的关系以及指针与数组和函数的交互。文章还探讨了动态内存分配和常见指针错误及其调试方法,提供了丰富的C++指针资料。

指针的基本概念

什么是指针

在C++中,指针是一种数据类型,用于存储内存地址。指针本身占用一定的内存空间,但其值是指向其他内存地址的指针。指针可以指向任何数据类型,包括基本数据类型(如整型、浮点型等)和用户自定义的数据类型(如结构体和类)。

如何声明和使用指针

要声明一个指针,需使用星号*来表示该变量是一个指针。例如,声明一个指向整型的指针如下所示:

int *p;

这里p是一个指向整型的指针。为了使指针指向某一特定内存地址,可以将变量的地址赋值给指针。例如:

int a = 10;
int *p = &a;  // p指向变量a的地址

通过这种方式,指针p存储了变量a的地址。可以通过指针来访问它指向的数据,使用*解引用操作符。例如:

*p = 20;  // 通过指针修改a的值

此时,变量a的值将变为20。

指针的简单操作

指针支持常见的算术运算,如加法、减法等。这些运算通常用于数组和字符串操作。指针的自增、自减等操作不仅能够移动指针到下一个或前一个元素,也能通过指针计算内存地址。例如:

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // p指向数组的第一个元素

p++;  // 移动到下一个元素
*p = 10;  // 修改arr[1]的值为10

cout << *(p-1) << endl;  // 输出arr[0]的值

下面是一个简单的C++程序,展示如何声明、初始化、赋值和解引用指针:

#include <iostream>

int main() {
    int num = 10;
    int *ptr = &num;  // ptr是一个指向整型的指针

    std::cout << "Address of num: " << &num << std::endl;
    std::cout << "Value of num: " << num << std::endl;
    std::cout << "Value of *ptr: " << *ptr << std::endl;

    *ptr = 20;  // 通过指针修改num的值
    std::cout << "Updated value of num: " << num << std::endl;

    return 0;
}

指针与内存地址

内存地址的概念

内存地址是存储在计算机内存中的每个字节的唯一标识符。每个变量都有一个唯一的内存地址,可以通过指针访问这些地址。在C++中,&操作符用来获取变量的地址,而*操作符用来解引用指针,获取指针所指向的值。

如何通过指针访问内存地址

要通过指针访问内存地址,首先需要声明并初始化一个指针,然后通过*操作符访问指针所指向的值。例如:

int x = 5;
int *ptr = &x;
cout << *ptr << endl;  // 输出5

这里,ptr指向变量x的内存地址,*ptr表示访问ptr所指向的地址中的数据。

指针与变量的关联

指针能够方便地修改其指向的变量的值。例如:

int num = 42;
int *ptr = &num;  // ptr指向num
*ptr = 100;  // 修改num的值为100
cout << num << endl;  // 输出100

通过指针可以间接地修改变量的值,这在需要动态修改数据结构中的元素时非常有用。

指针与数组

指针与数组的关系

数组在内存中是连续存放的,因此,指针可以很方便地用于遍历数组。数组名本身就是一个指向数组第一个元素的指针。例如:

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // p指向arr的第一个元素

如何用指针遍历数组

遍历数组可以通过指针的递增操作来实现。例如:

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // p指向arr的第一个元素

for (int i = 0; i < 5; i++) {
    cout << *p << endl;
    p++;  // 移动指针到下一个元素
}

数组指针与指针数组的区别

数组指针是指向数组的指针,而指针数组是一个数组,其每个元素都是指针。例如:

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;  // ptr是一个指向int数组的指针
int *arrPtr[3];  // arrPtr是一个包含3个int指针的数组

arrPtr[0] = &arr[0];  // 让arrPtr[0]指向arr的第一个元素
arrPtr[1] = &arr[1];  // 让arrPtr[1]指向arr的第二个元素
arrPtr[2] = &arr[2];  // 让arrPtr[2]指向arr的第三个元素

指针与函数

函数参数中的指针

函数可以通过指针参数来修改调用者传递的数据。例如:

void Modify(int *a) {
    *a = 100;  // 修改指针指向的值
}

int main() {
    int x = 42;
    Modify(&x);  // 传入x的地址
    cout << x << endl;  // 输出100
    return 0;
}

函数返回值为指针

函数可以返回一个指针,返回的指针可以指向函数内部创建的局部变量或其他数据结构。例如:

int* CreateInt() {
    int x = 42;
    return &x;  // 返回x的地址
}

int main() {
    int *ptr = CreateInt();
    cout << *ptr << endl;  // 输出42
    return 0;
}

需要注意的是,返回的指针指向的局部变量在函数返回后可能会变为无效地址。

指针作为函数指针的使用

函数指针是指向函数的指针,可以用来调用相应的函数。例如:

void FunctionA() {
    cout << "Function A" << endl;
}

void FunctionB() {
    cout << "Function B" << endl;
}

void CallFunction(void (*func)()) {
    func();  // 调用func指向的函数
}

int main() {
    void (*func)() = FunctionA;
    CallFunction(func);  // 输出 "Function A"
    func = FunctionB;
    CallFunction(func);  // 输出 "Function B"
    return 0;
}

动态内存分配

使用newdelete操作符

new操作符用于分配内存,而delete操作符用于释放内存。例如:

int *p = new int;  // 分配一个int的内存
*p = 42;  // 给分配的内存赋值
cout << *p << endl;  // 输出42
delete p;  // 释放内存
p = nullptr;  // 将指针置为nullptr

动态数组的创建与释放

动态数组的创建与释放可以通过new[]delete[]操作符来实现。例如:

int *arr = new int[5];  // 分配一个包含5个int的数组
for (int i = 0; i < 5; i++) {
    arr[i] = i;
}
for (int i = 0; i < 5; i++) {
    cout << arr[i] << " ";
}
delete[] arr;  // 释放整个数组
arr = nullptr;  // 将指针置为nullptr

指针在动态内存中的应用

指针在动态内存中的应用非常广泛,可以用来创建复杂的数据结构,如链表、树等。例如:

struct Node {
    int data;
    Node *next;
};

Node *createNode(int value) {
    Node *newNode = new Node;
    newNode->data = value;
    newNode->next = nullptr;
    return newNode;
}

int main() {
    Node *head = createNode(10);
    head->next = createNode(20);
    head->next->next = createNode(30);

    Node *current = head;
    while (current != nullptr) {
        cout << current->data << " ";
        current = current->next;
    }
    cout << endl;

    // 释放内存
    while (head != nullptr) {
        Node *temp = head;
        head = head->next;
        delete temp;
    }

    return 0;
}

指针的常见错误与调试

空指针与野指针

空指针是指向nullptr的指针,而野指针是指向未知地址的指针。空指针通常用于标记指针未被初始化或指向无效地址;而野指针则可能导致程序崩溃。例如:

int *ptr = nullptr;  // 空指针
if (ptr == nullptr) {
    cout << "ptr is a null pointer" << endl;
}

int *wildPtr = (int *)0x12345678;  // 野指针
// 使用wildPtr可能导致程序崩溃

指针操作的常见陷阱

常见的指针操作陷阱包括指针越界、释放已经释放的内存、指针类型转换错误等。例如:

int *ptr = new int[10];
*(ptr + 10) = 42;  // 指针越界
delete ptr;
delete ptr;  // 释放已经释放的内存

如何避免和调试指针错误

避免和调试指针错误的方法包括初始化指针、检查指针是否为空、合理使用newdelete、避免类型转换错误等。使用工具如Valgrind或AddressSanitizer等可以帮助检测内存泄漏和指针错误。例如:

int *ptr = nullptr;
ptr = new int[10];  // 初始化指针
if (ptr != nullptr) {
    for (int i = 0; i < 10; i++) {
        ptr[i] = i;
    }
}

delete[] ptr;  // 正确释放内存
ptr = nullptr;  // 将指针置为nullptr
打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP