C++指针篇

#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>

typedef void (*FF)(int a, int b);

struct Point {
    int x;
    int y;
};

struct Person
{
    int x;
    int y;
};

void Test9(int a, int b);    // 函数声明

int* Test10();

int main() {

    int a = 10;
    int* point = &a; // 声明一个指针变量point,point是指向int类型的一个指针
    // 指针也是一个变量,只不过这个变量有点特殊,这个变量存储的是一个变量的地址
    
    std::cout << point << std::endl;    // 这里是输出指针变量的地址
    std::cout << *point << std::endl;    // 对指针解引用。解引用就是获取指针变量中地址所指向的值

    // 通过指针变量来对值操作
    *point = *point + 1;
    std::cout << *point << std::endl;

    // 2. 指针的危险
    // 在C++中创建指针时,计算机将分配一个内存空间,用来存储地址。但不会存储这个地址指向数据的内存
    long* fellow; // 创建一个long类型的指针变量
    //*fellow = 2233323; // 编译器会警告的、编译失败
    // 指针指向哪里呢?并没有将地址赋值给fellow,2233323放到哪里呢?我们不知道的
    // 可能是任何值,也可能指向的地方不是2233323要放的地方.会出现错误

    // 3. 指针和数字
    // 指针不是整型
    int* pt;
    //pt = 0xB8000000;    // 这样并不匹配

    pt = (int*)0xB80000; // 这样才算匹配,强制转换

    // 4. 使用new来分配内存
    // 使用new来分配的内存是存放在堆空间中的, 普通声明变量是存储在栈内存中的
    int* pn = new int;
    // 使用new关键字在内存去寻找内存,内存的大小是四个字节,返回第一个字节的地址
    // 特殊化一点
    int* pn2 = new int(10);
    
    std::cout << *pn2 << std::endl;

    // 5. 使用delete 关键字释放内存
    // C++没有垃圾回收机制,程序员手动申请的内存。是需要手动释放掉的
    delete pn;
    delete pn2;

    // C风格类型的指针
    //int* pn3 = (int*)malloc(sizeof(4));
    //delete pn3;

    // 6. 动态数组
    // 什么是动态数组?什么是静态数组?
    // 动态数组是通过new 关键字来申请内存空间,在运行期间确认。静态数组是在编译期都声明好了
    int a1[10]; // 静态数组

    //int* b = new int[20];    // 动态数组
    //// 动态数组初始化
    //for (int i = 0; i < 20; i++) {
    //    *(b + i) = i;
    //}
    //// 动态数组初始化
    //for (int i = 0; i < 20; i++) {
    //    std::cout << *(b + i) << std::endl;
    //}
    //
    //// 释放动态数组:两种释放方式
    //delete[] b;
    //delete b; 不建议用这种语法

    // 7. 数组和指针
    // (指针表示法、数组表示法)
    int* arr1;
    int arr4[] = { 1,2,3,4,5,6 };

    arr1 = arr4;    // arr4是数组中第一个元素的地址
    //    多数情况下:C++将数组名解释为数组中第一个元素的地址

    std::cout << arr1 << std::endl; // 第一个元素的地址
    std::cout << *arr1 << std::endl; // 地址所指向的值

    std::cout << arr1 + 1 << std::endl;    // 第二个元素的地址;
    std::cout << *(arr1 + 1) << std::endl; // 第二个元素的内容;

    std::cout << arr1 + 2 << std::endl;    // 第三个元素的地址
    std::cout << *(arr1 + 2) << std::endl;    // 第三个元素的地址

    std::cout << arr1[4] << std::endl;    // 数组表示法
    
    // *(arr1 + 1) 与 arr1[1] 是等价的
    
    // sizeof的使用
    std::cout << sizeof(arr1) << std::endl; // sizeof对指针使用就是获取指针的长度
    std::cout << sizeof(arr4) << std::endl;    // sizeof对数组得到是数组的长度

    // delete arr1 可以么?不可以,这是数组arr4分配的固定内存。不能由程序员手动释放内存
    
    // 直接输出数组的名字会是什么呢?
    std::cout << arr4 << std::endl;    //       这里是arr4的地址
    std::cout << &arr4 << std::endl;    // 这里是arr4的地址

    // 8. 字符串和指针
    // 指针和数组可以拓展到C风格的字符串
    // C风格的字符串
    char ch4[] = "abcdefg";
    char ch5[10] = { '1','2','3','\0' };
    
    char* ch6; // 声明一个字符型的指针
    ch6 = ch4; // 把字符串的第一个数的地址赋值给ch6
    
    std::cout << ch6 << std::endl;    // cout对象认为ch6的地址是字符串的首地址,就会一直打印,直到遇到\0
    // 总之,给cout一个字符的地址,就会一直打印。直到遇到空字符为止。
    
    char animal[20] = "bear";    // 字符串
    const char* bird = "wren";    // 这里是把字符串 "wren"的地址赋值给bird
    char* ps;

    std::cout << animal << std::endl;
    std::cout << bird << std::endl;
    // std::cout << ps << std::endl;
    
    std::cin >> animal; // 如果输入长度小于20
    ps = animal; // 把字符串的首地址赋值给ps

    std::cout << "Before using strcpy(): \n";
    std::cout << animal << " at " << (int*)animal << std::endl;    // 强制转换 int*地址

    std::cout << strlen(animal) << std::endl;

    // 手动申请内存,长度为 animal + 1,C风格字符串有一个空符号做结束符
    ps = new char[strlen(animal) + 1];

    strcpy_s(ps, strlen(animal) + 1, animal);

    std::cout << "After using strcpy():\n";

    std::cout << animal << " at " << (int*)animal << std::endl;
    std::cout << ps << " at " << (int*)ps << std::endl;

    delete[] ps;    // 释放掉内存

    // 9. 指针和结构
    Person person;
    person.x = 10;
    person.y = 20;

    Person* _person = &person;

    // 如何访问结构指针的数据?
    std::cout << _person->x << std::endl;
    std::cout << _person->y << std::endl;

    // 通过new 关键字创建结构
    Person* person2 = new Person{ 20,22 };
    person2->x = 10;
    person2->y = 30;
    std::cout << person2->x << std::endl;
    std::cout << person2->y << std::endl;

    std::cout << (*person2).x << std::endl;
    std::cout << (*person2).y << std::endl;

    // 10. 字符串指针数组
    // 在C++中,数组 {"hello", "world"} 中字符串是 const char*s,所以数组必须const
    const char* b[] = { "hello", "world" };

    // 基本数据类型的指针数组
    int arr10[] = { 1,2,3,4 };
    int* arrtt[4];
    for (int i = 0; i < 4; i++) {
        arrtt[i] = &arr10[i];
    }
    
    // 11. 引用& 变量的别名,和变量指向同一个地址、值也一样
    // 引用在定义的时候,需要初始化

    int temp = 10;
    int temp3 = 23;
    int& temp2 = temp;
    std::cout << temp << ";" << temp2 << std::endl;

    // 12. 指针常量和常量指针

    // 常量指针,所指向的内容是不可以修改的
    // 但是它是一个指针,可以更改指针的指向
    // 定义的时候必须初始化
    const int* tt = &temp;
    tt = &temp3;
    //*tt = *tt + 1;    

    // 指针常量
    // 指针常量本质上指针是一个常量,不可以改变指针的指向,但是指针指向的内容是可以修改的
    int* const tt2 = &temp;
    *tt2 = *tt2 + 1;

    // 13. 函数指针和指针函数
    
    // 函数指针本质上也是一个指针,只不过指针是指向的一个函数
    void (*func)(int, int); // 返回值 (指针名) (形参)
    // 可以使用typedef起个别名,在函数声明之前
    FF f = Test9;
    f(10, 20);
    
    // 指针函数,就是返回值为指针的一个函数
    int* tee = Test10();
    delete tee;

    // 14. 空指针
    int* ttt = nullptr;

    return 0;
}

void Test9(int a, int b) {
    std::cout << a + b << std::endl;
}

int* Test10() {
    int* p = new int;
    return p;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值