C++学习之指针

简介: C++学习之指针

C++ 指针介绍

指针是C++语言中非常重要的概念,它提供了对内存中数据的直接访问方式。指针存储了一个变量的内存地址,可以通过指针来访问和操作该变量。

以下是指针的一些基本介绍:

  1. 定义指针:在C++中,可以使用*(星号)来声明一个指针变量。例如,int* ptr;声明了一个名为ptr的指向整数的指针变量。需要注意的是,指针变量在声明时应初始化为一个有效的内存地址。
  2. 获取变量地址:使用取地址运算符&可以获取一个变量的内存地址。例如,int num = 10; int* ptr = #ptr指向num的地址。
  3. 解引用指针:使用解引用运算符*可以访问指针所指向的变量的值。例如,int num = 10; int* ptr = &num; std::cout << *ptr;会输出10,即ptr指向的num的值。
  4. 动态内存分配:使用new关键字可以在程序运行时动态地分配内存空间。例如,int* ptr = new int;会在堆上分配一个整数大小的内存,并将其地址赋给ptr
  5. 删除动态分配的内存:使用delete关键字可以释放通过new分配的动态内存。例如,delete ptr;会释放由ptr指向的内存。
  6. 空指针:空指针指向内存地址0,表示指针不指向任何有效的对象。可以使用nullptrNULL来初始化或比较指针变量是否为空。
  7. 指针算术:指针可以进行算术运算,如指针的加法、减法等。这些运算会根据指针类型的大小来改变指针指向的地址。

指针在C++中非常灵活和强大,可以用于许多方面,如数组访问、动态内存管理、函数交互等。然而,需要小心处理指针,因为不正确的指针操作可能导致程序崩溃或内存泄漏等问题。

C++指针声明和使用

当声明和使用C++指针时,可以按照以下方式进行:

  1. 声明指针:使用*来声明一个指针变量,表示该变量将存储某个类型的内存地址。例如,声明一个指向整数的指针:
int* ptr;
  1. 初始化指针:可以使用取地址运算符&来获取一个变量的地址,并将其赋值给指针变量。例如,将一个整数变量的地址赋值给指针:
int num = 10;
int* ptr = &num;
  1. 解引用指针:使用解引用运算符*来访问指针所指向的变量的值。例如,输出指针所指向的整数变量:
std::cout << *ptr;
  1. 动态分配内存:使用new关键字可以在程序运行时动态地分配内存。例如,动态分配一个整数大小的内存,并使用指针来引用它:
int* ptr = new int;
  1. 释放内存:使用delete关键字释放通过new分配的内存。例如,释放先前动态分配的内存:
delete ptr;

下面是一个完整的示例,演示了指针的声明、初始化、解引用和动态内存分配等操作:

#include <iostream>
int main() {
  int num = 20;
  int* ptr = &num;
  std::cout << "Pointer value: " << *ptr << std::endl;
  std::cout << "Memory address: " << ptr << std::endl;
  int* dynamicPtr = new int;
  *dynamicPtr = 30;
  std::cout << "Dynamic pointer value: " << *dynamicPtr << std::endl;
  delete dynamicPtr;
  return 0;
}

这个示例中,首先定义了一个整数变量num和一个指向整数的指针ptr,并输出了指针所指向的值和地址。接下来,使用new动态分配了一个整数大小的内存,并将其地址赋值给dynamicPtr,然后输出了该指针所指向的值。最后,通过delete释放了动态分配的内存。

C++的指针常量和常量指针

C++中的指针常量和常量指针是两种不同类型的指针,它们具有不同的特性。下面分别举例说明:

  1. 指针常量(Pointer to Constant):指针常量是指指针本身是常量,即指针所指向的地址不能变化,但它所指向的值可以修改。声明一个指针常量时需要在*前加上const关键字。
int num = 10;
const int* ptr = &num;

在这个例子中,ptr是一个指向整数常量的指针。这意味着ptr可以指向不同的整数,但无法通过ptr来修改所指向的整数的值。以下操作是合法的:

int anotherNum = 20;
ptr = &anotherNum; // 指针可以指向不同的整数

但以下操作是不合法的,会导致编译错误:

*ptr = 30; // 无法通过指针来修改所指向的整数值
  1. 常量指针(Constant Pointer):常量指针是指指针本身可变,即指针所指向的地址可以变化,但它所指向的值不可修改。在声明一个常量指针时需要在指针名前加上const关键字。
int num = 10;
int* const ptr = &num;

在这个例子中,ptr是一个常量指针,它指向一个整数。这意味着ptr所指向的地址不能改变,一旦指向了一个地址,就无法通过ptr来指向其他地址。以下操作是合法的:

*ptr = 20; // 可以通过指针来修改所指向的整数的值

但以下操作是不合法的,会导致编译错误:

int anotherNum = 30;
ptr = &anotherNum; // 无法更改指针所指向的地址

通过理解指针常量和常量指针的概念和用法,可以更好地控制和管理指针在程序中的行为。在实际应用中,根据需求选择使用适当类型的指针可以提高代码的可读性和安全性。

C++指针和数组

在C++中,指针和数组可以紧密结合使用。指针可以用于访问和操作数组的元素,通过指针可以实现对数组的遍历、修改和传递等操作。以下是一些示例:

  1. 声明指向数组的指针:可以使用*声明一个指向数组的指针。
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr;

在这个例子中,ptr是一个指向整数数组arr的指针。指针ptr指向数组的第一个元素。

  1. 使用指针遍历数组:可以通过指针来遍历数组,以访问和修改数组的元素。
for (int i = 0; i < 5; i++) {
  std::cout << *(ptr + i) << " "; // 输出数组元素的值

这里使用指针ptr遍历数组arr*(ptr + i)表示指针移动到当前索引位置的元素。通过循环输出数组的元素。

  1. 使用指针修改数组的值:指针也可以用于修改数组元素的值。
*(ptr + 2) = 10;

这行代码会将数组中索引为2的元素的值修改为10。

  1. 将指针作为函数参数:指针可以作为函数的参数,用于传递数组。
void printArray(int* arr, int size) {
  for (int i = 0; i < size; i++) {
    std::cout << arr[i] << " ";
  }
}
int main() {
  int arr[5] = {1, 2, 3, 4, 5};
  printArray(arr, 5);
  return 0;
}

在这个例子中,printArray函数接受一个指向整数的指针arr和数组大小size作为参数。在main函数中,将数组arr和数组大小传递给printArray函数来打印数组的元素。

通过指针和数组的结合使用,可以更灵活地操作和处理数组数据。需要注意的是,在使用指针访问数组时要确保不越界,以避免错误和未定义行为的发生。

C++ 指针,数组分别做函数参数

在C++中,指针和数组作为函数参数时有多种情况。下面举例说明一些常见情况:

  1. 将指针作为函数参数:
void modifyValue(int* ptr) {
  *ptr = 10;
}
int main() {
  int num = 5;
  modifyValue(&num);
  std::cout << num; // 输出:10
  return 0;
}

在这个例子中,modifyValue函数接受一个指向整数的指针ptr。通过引用传递(或传递指针的地址),函数可以修改指针指向的变量的值。

  1. 将数组作为函数参数(指针形参):
void modifyArray(int* arr, int size) {
  for (int i = 0; i < size; i++) {
    arr[i] *= 2;
  }
}
int main() {
  int arr[5] = {1, 2, 3, 4, 5};
  modifyArray(arr, 5);
  for (int i = 0; i < 5; i++) {
    std::cout << arr[i] << " "; // 输出:2 4 6 8 10
  }
  return 0;
}

在这个例子中,modifyArray函数接受一个指向整数的指针arr和数组大小size作为参数。通过指针形参,函数可以修改数组元素的值。

  1. 将数组作为函数参数(使用数组形参):
void modifyArray(int arr[], int size) {
  for (int i = 0; i < size; i++) {
    arr[i] *= 2;
  }
}
int main() {
  int arr[5] = {1, 2, 3, 4, 5};
  modifyArray(arr, 5);
  for (int i = 0; i < 5; i++) {
    std::cout << arr[i] << " "; // 输出:2 4 6 8 10
  }
  return 0;
}

这个例子与前一个例子相似,不同之处在于这里使用了数组形参,函数参数中的int arr[]实际上是一个指针,它和第二个例子中的int* arr形式是等价的。

无论是将指针还是数组作为函数参数,都可以在函数内部修改它们所指向的数据。需要注意的是,在函数内部修改数组时,要确保不越界访问数组的元素,以避免引发错误或未定义行为。

C++ 指针在参数传递中的各种情况

在C++中,指针在参数传递中有以下几种情况:

  1. 将指针作为参数传递:
void modifyPointer(int* ptr) {
  int num = 10;
  ptr = &num; // 修改指针指向的地址
}
int main() {
  int* ptr = nullptr;
  modifyPointer(ptr);
  std::cout << ptr; // 输出:nullptr
  return 0;
}

在这个例子中,modifyPointer函数接受一个指向整数的指针ptr作为参数。函数内部修改了指针的值(即指向了另一个地址),但是这个改变不影响函数外部的指针。

  1. 将指针的引用作为参数传递:
void modifyPointer(int*& ptr) {
  int num = 10;
  ptr = &num; // 修改指针的引用
}
int main() {
  int* ptr = nullptr;
  modifyPointer(ptr);
  std::cout << ptr; // 输出:0x[某个地址]
  return 0;
}

在这个例子中,modifyPointer函数接受一个指向整数的指针的引用ptr作为参数。通过将指针的引用传递给函数,函数可以修改指针本身的值,这会影响函数外部的指针。

  1. 将指向指针的指针作为参数传递:
void modifyDoublePointer(int** pptr) {
  int num = 10;
  *pptr = &num; // 修改指针的指针
}
int main() {
  int* ptr = nullptr;
  int** pptr = &ptr;
  modifyDoublePointer(pptr);
  std::cout << *pptr; // 输出:0x[某个地址]
  return 0;
}

在这个例子中,modifyDoublePointer函数接受一个指向指针的指针pptr作为参数。通过间接访问,函数可以修改指针指向的地址,从而影响函数外部的指针。

指针在参数传递中非常灵活,可以根据需求选择合适的方式来传递指针,以实现对指针自身或指向的数据进行修改。需要注意的是,在修改指针指向的数据时,要注意避免访问已经释放的内存或导致未定义行为的操作。

C++ 指针错误用法

下面是一些常见的C++指针错误用法的例子:

  1. 未初始化指针:
int* ptr;
*ptr = 10; // 未初始化的指针无效,会导致未定义行为

这里ptr是一个未初始化的指针,对未初始化的指针进行解引用操作会导致未定义行为,可能会引发程序崩溃。

  1. 使用空指针:
int* ptr = nullptr;
*ptr = 10; // 空指针无效,会导致未定义行为

这个例子中,将整型指针ptr设置为nullptr,然后试图通过解引用操作给空指针赋值,这也会导致未定义行为。

  1. 访问超出范围的指针:
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = &arr[0];
*(ptr + 6) = 10; // 越界访问,会导致未定义行为

在这个例子中,指针ptr指向数组arr的第一个元素,在试图访问存储在第7个位置上的元素时,超出了数组的范围,这会导致未定义行为。

  1. 错误释放内存:
int* ptr = new int(5);
delete ptr;
*ptr = 10; // 已删除的内存再次使用,会导致未定义行为

这个例子中,使用new动态分配了一个整型对象,并用指针ptr进行指向。之后通过delete释放了该内存,并尝试重复使用已被释放的内存空间,这会导致未定义行为。

  1. 悬空指针:
int* getPtr() {
  int num = 5;
  return &num; // 返回了函数作用域内的局部变量的地址
}
int main() {
  int* ptr = getPtr();
  *ptr = 10; // 悬空指针,会导致未定义行为
  return 0;
}

这个例子中,在函数getPtr中返回局部变量num的地址,当指针ptr尝试访问这个地址时,访问的是一个已经超出作用域的局部变量,这也会导致未定义行为。

避免这些指针错误的发生,需要注意在使用指针时,确保指针是有效的、已初始化的,并正确地管理动态分配的内存。

关注我,不迷路,共学习,同进步

关注我,不迷路,共学习,同进步

相关文章
|
5天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
25 4
2023/11/10学习记录-C/C++对称分组加密DES
|
5天前
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
23 0
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
88 4
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
2月前
|
存储 C++
c++的指针完整教程
本文提供了一个全面的C++指针教程,包括指针的声明与初始化、访问指针指向的值、指针运算、指针与函数的关系、动态内存分配,以及不同类型指针(如一级指针、二级指针、整型指针、字符指针、数组指针、函数指针、成员指针、void指针)的介绍,还提到了不同位数机器上指针大小的差异。
61 1
|
2月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
44 2
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
27 1
|
2月前
|
C语言
学习——理解指针(4)(指针学习最后一节)
学习——理解指针(4)(指针学习最后一节)
|
2月前
|
存储 C++
学习——理解指针(3)
学习——理解指针(3)