首页 > 编程语言 >C++指针基础

C++指针基础

时间:2023-10-24 20:44:18浏览次数:32  
标签:变量 指向 int cout 基础 内存空间 C++ 指针

指针基础

目录

引用

引用变量是对现有变量的引用,它是使用 & 运算符创建的:

string food = "Pizza";  // 声明 food 变量
string &meal = food;    // 引用 food
  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。
#include <iostream>
using namespace std;
int main()
{
   // 声明简单的变量
   int i;
   double d;

   // 声明引用变量
   int &r = i;
   double &s = d;

   i = 5;
   cout << "value of i : " << i << endl;
   cout << "value of i reference : " << r << endl;

   d = 11.7;
   cout << "value of d : " << d << endl;
   cout << "value of d reference : " << s << endl;

   return 0;
}


// value of i : 5
// value of i reference : 5
// value of d : 11.7
// value of d reference : 11.7

为了了解动态内存,首先需要了解指针。我们创建的所有变量都存储在内存中。

指针是一个变量,它将另一个变量的内存地址存储为其值。

定义和访问

int *p;      // 数值类型
p=&a;       // 记录变量a的地址 

必要时要加( ) 来避免优先级的问题
int(*p_arr)[3];    //指向含有3个int元素的数组的指针 
Student* p_struct;     //类或结构体类型的指针
使用 & 运算符访问变量的地址。
使用 * 定义一个指针类型。

int num = 42;

int *p = &num;

cout << p;

使用 星号 * 还用于访问存储在内存地址的值。它称为解除引用运算符
cout << *p;

案例

#include <iostream>

using namespace std;

int main() {
    int num = 42;

    int *p = &num;

    cout << "nums " << num << endl;
    cout << "*p " << p << endl;
    cout << "**p " << *p << endl;

    return 0;
}

// 执行结果
nums 42
*p 0x3bfb3ff894
**p 42

内存空间

在32位操作系统下占用4个字节,64位下占用8个

空指针和野指针

空指针:指针变量指向内存编号为0的空间

用途:初始化指针变量

注意:空指针指向的内存是不可以访问的

野指针:指变量指向非法的内存空间

const修饰指针

const修饰指针----常量指针

特点:指针的指向可以修改,指针指向的值不可以修改

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int b = 20;
    const int *p = &a;
    *p = 20;  // --错
    p = &b;   // --对
}

const修饰常量----指针常量

特点:指针的指向不可以修改,指针指向的值可以修改

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int b = 20;
    int *const p = &a;

    *p = 20;  // --对
    p = &b;   // --错
}

指针之间的赋值

指针赋值和int变量赋值一样,就是将地址的值拷贝给另外一个。

指针之间的赋值是一种浅拷贝,是在多个编程单元之间共享内存数据的高效的方法。

int* p1  = &a;
int* p2 = p1;

通过指针改变原数据值

int num = 42;
int *p = &num;

*p = 8;
cout << num;
8

指针和数组

数组的名称实际上是指向其第一个元素的指针。

可以通过递增指针来访问每个元素。

案例1

#include <iostream>
using namespace std;

int main() {

    int arr[] = {2, 4, 6, 8};   // 数组
    int *p = arr;                             // 数组指针-指向了数组的第一个元素

    // 第一个元素
    cout << *p << endl;

    // 第二个元素
    cout << *(p + 1) << endl;

    // 第三个元素
    cout << *(p + 2) << endl;

    return 0;
}

// 执行结果
2
4
6

案例2

#include <iostream>
using namespace std;

int main() {
    int arr2[] = {44, 22, 11, 0};

    int *p2 = arr2;

    for (int i = 0; i < 4; i++) {
        cout << *p2 << endl;
        p2++;
    }

    return 0;
}

44
22
11
0

说明

& 运算符用于访问变量的内存位置。
* 运算符用于访问存储在指针中的内存地址的值。
同样的 * 符号也用于声明指针,它与解除引用运算符不同。

指针和函数

1.值传递

2.地址传递

#include<iostream>
using namespace std;

void swap(int a, int b) {
    int temp = 0;
    temp = a;
    a = b;
    b = temp;
}

void swap2(int *a, int *b) {
    int temp = *a;   // 解指针得到数值
    *a = *b;   
    *b = temp;
}

int main() {
    int a = 10;
    int b = 20;
    //值传递
    swap(a, b);
    cout << a << " " << b << endl;
    //地址传递
    swap2(&a, &b);
    cout << a << " " << b << endl;
    return 0;
}

// 执行结果
10 20
20 10

动态内存

我们需要根据用户输入分配新内存时。 创建动态数组(具有可变大小的数组)

#include <iostream>

using namespace std;

int main() {
    int size = 10;

    int *p = new int[size];    // 通过new来创建一个数组指针

    for (int i = 0; i < size; i++) {
        p[i] = i * i;
    }

    for (int i = 0; i < size; i++) {
        cout << p[i] << ends;
    }
}
0 1 4 9 16 25 36 49 64 81

指针潜在危险

指针的让我们对内存的操作有了很大的自由性,同时也带来了潜在的危险。

产生的原因:

1.定义指针变量的同时未对其进行初始化:
指针在被定义的时候,如果程序不对其进行初始化的话,它会指向随机区域,
因为任何指针变量(除了static修饰的指针变量)在被定义的时候是不会被置空的,它的默认值是随机的。

2.指针所指向的内存空间被释放时,却没有对该指针变量的值(即该指针原来指向的内存空间的地址)进行置空:
我们在用库函数malloc开辟内存空间时,要检查返回值是否为空,如果为空,则开辟失败;如果不为空,则指针指向的是开辟的内存空间的首地址。
指针指向的内存空间在用free()或者delete(注意delete只是一个操作符,而free()是一个函数)
释放后,如果程序员没有对其置空或者其他的赋值操作,就会使其成为一个野指针。

3.指针操作超越变量作用域.

危害规避

1.在定义一个指针时同时初始化为NULL
int *p=NULL;

2.释放指针指向的内存空间时,将指针重置为NULL。
free(p1);        //只释放了p1指向的堆区空间  并没有将指针p1置为空
p1 = NULL;

3..使用时不要超出变量作用
int a[3];
int*p=a;
cout<<p[5];   // 错误使用

参考资料

https://mp.weixin.qq.com/s/cgybk0JWaxPouCJ66vOlGQ

标签:变量,指向,int,cout,基础,内存空间,C++,指针
From: https://www.cnblogs.com/tian777/p/17785716.html

相关文章

  • CTFshow逆向题目wp(1):基础篇
    re11.查看文件信息,64位elf文件2.使用64位ida打开,发现flag......
  • Java基础 缓冲流为什么能提高性能?
    缓冲流为什么能提高性能?知识点:1个字节=1B缓冲流自带长度为8192的缓冲区,字节缓冲流的缓冲区是byte类型的,是长度为8192的字节数组,为8K;而字符缓冲流的缓冲区是char类型的,是长度为8192的字符数组,为16K,因为 Java中一个字符占两个字节通过缓冲区可以显著提高字节流......
  • Java基础 字符缓冲流
      字符流的基本流本身其实已经有缓冲区了,所以字符缓冲流提高的效率不是很明显。 字符缓冲流的构造方法:字符缓冲输入流:public BufferedReader(Reader r)  →  把基本流变成高级流字符缓冲输出流:public BufferedWriter(Writer r)  →  把基本流变成......
  • python基础语法指南
    输出流输出百分号(1)直接使用参数格式化:{:.2%}{:.2%}:显示小数点后2位print('percent:{:.2%}'.format(42/50))percent:84.00%不显示小数位:{:.0%},即,将2改为0print('percent:{:.0%}'.format(42/50))percent:84%(2)格式化为float,然后处理成%格式:{:.2f}%需要对42/50乘......
  • 多年学习django经验markdown总结,基础到高手,共计50页,10大模块。 第(1)期
    Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以"插件"形式服务于整个框架,Django有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展性。它还强调快速开发和DRY(DoNotRepeatYourself)原......
  • Java基础 字节缓冲流、字节缓冲流拷贝文件
    字节缓冲流:原理:底层自带了长度为8192的缓冲区。利用缓冲区可以一次读写8192个字节,从而提高性能public BufferedInputStream(InputStream is)  →  把基本流包装成高级流,提高读取数据的性能public BufferedOutputStream(OutputStream os)  →  把基本......
  • Flask后端开发(一)-基础知识和前期准备
    目录1.背景介绍1.1.项目背景1.2.项目难点1.3.项目环境2.flask后端开发实现的功能3.flask部署和前后端对接3.1.flask运行配置和服务器部署3.2.flask前后端传参4.后端测试工具4.1.工具介绍4.2.工具使用后记1.背景介绍1.1.项目背景就是前几个月临时接手了一个后端项......
  • 【Python 千题 —— 基础篇】进制转换:十进制转二进制
    题目描述题目描述计算机底层原理中常使用二进制来表示相关机器码,学会将十进制数转换成二进制数是一个非常重要的技能。现在编写一个程序,输入一个十进制数,将其转换成二进制数。输入描述输入一个十进制数。输出描述程序将输入的十进制数转换为二进制数,并输出其二进制形式。示例示例......
  • Java基础 缓冲流
    缓冲流是高级流,它对基本流做了一个包装,所以在底层,真正读写数据的还是InputStream和OutputStream这两个基本流,只不过有了缓冲流的加持,读写的效率更高而已  ......
  • 【每天例题】蓝桥杯 c++ 卡片
    卡片题目小蓝有k种卡片,—个班有n位同学,小蓝给每位同学发了两张卡片,—位同学的两张卡片可能是同一种,也可能是不同种,两张卡片没有顺序。没有两位同学的卡片都是一样的。小蓝有k种卡片,-个班有n位同学,小蓝给每位同学发了两张卡片,-位同学的两张卡片可能是同一种,也可能是不同种,......