C++基础入门详细笔记(二)

C++基础入门详细笔记(一)

C++基础入门详细笔记(二)

C++基础入门详细笔记(三)

C++基础入门详细笔记(四)

C++基础入门详细笔记(五)

C++基础入门详细笔记(六)

 

目录

四、指针

1、空指针

2、void*指针

3、引用

4、指针和引用

5、指针和数组

6、指针的算数运算

6.1、指针的递增和递减(++、--)

6.2、指针加上或减去某个整数值

7、数组与指针小结

7.1、一维数组与指针

7.2、二维数值与指针

8、动态分配内存

8.1、使用new分配内存

8.2、使用delete释放内存

9、动态分配数组

9.1、使用new创建动态分配的数组

9.2、使用delete[]释放内存

9.3、程序的内存分配

10、总结


四、指针

int *ptr_year;
ptr_year=&year;    //&year表示取地址

注意:

1. int* p的写法偏向于地址,即p就是一个地址变量,表示一个十六进制地址

2. int *p的写法偏向于值,*p是一个整形变量,能够表示一个整型值

3. 声明中的*号和使用中的*号含义完全不同

 

example:

#include <iostream>
using namespace std;
int main()
{
    char ch = 'a';
    char * ptr_ch = &ch;
    cout << (void *)ptr_ch << '\t' << *ptr_ch << endl;
    return 0;
}

> 结果输出:0x6dfeeb        a

(void *):任意类型指针

 

1、空指针

空指针不指向任何对象,在试图使用一个指针之前可以首先检查是否为空

用法

int *ptr1 = nullptr;//等价于int *ptr1 = 0;
int *ptr2 = 0;      //直接将ptr2初始化为字面常量0
//需要包含#include <stdlib.h>头文件
int *ptr3 = NULL;   //等价于int *ptr3=0;

 

2、void*指针

1. (void*)指针存放一个内存地址,地址指向的内容是什么类型不能确定

2. (void*)类型指针一般用来:拿来和别的指针比较、作为函数的函数的输入和输出;赋值给另一个(void*)指针

 

3、引用

int int_value = 1024;
//refValue指向int_value,是int_value的另一个名字

int& refValue = int_value;

//错误:引用必须被初始化
int& refValue2;

 

 

注:

  • 指向常量的引用是非法的
double & ref = 100;         //错误
const double & ref = 100;   //正确

 引用并非对象,只是为一个已经存在的对象起的别名

  • 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起
int &ref_value = 10;   //错误

 引用必须初始化,所以使用之前不需要测试其有效性,因此使用引用可能会比使用指针效率高

int * num = &abc;   //引用
  • 引用更接近const指针,一旦与某个变量关联起来,就将一直效忠于它

  • 将引用变量用作参数时,函数将使用原始数据,而非副本

  • 当数据所占内存比较大时,建议使用引用参数

4、指针和引用

1. 引用对指针进行了简单封装,底层仍然是指针

2. 获取引用地址时,编译器会进行内部转换

3.引用比指针效率高

int num = 108;
int& rel_num = num;
rel_num = 118;
cout << &num << '\t' <<&rel_num <<endl;

转换为:
 

int num = 108;
int* rel_num = &num;
*rel_num = 118;
cout << &num << '\t' <<rel_num <<endl;

 

 

5、指针和数组

数组:

1. 存储在一块连续的内存空间中

2. 数组名就是这块连续内存空间的首地址

#include <iostream>
using namespace std;
int main()
{
    double score[] {11, 22, 33, 44, 55};//数组类型-->double[5]
    double * ptr_score = score;
    
    //数组名就是这块连续内存空间的首地址
    //cout << score << endl;    //输出为地址值
    cout << sizeof(score) << ''\t' <<sizeof(ptr_score) <<endl
}

结果:40   4

解答:ptr_score为double型的地址,所以只占4个字节;而score为数组,占40字节。

 

6、指针的算数运算

6.1、指针的递增和递减(++、--)

int i;
double score[5] {98, 87, 65, 43, 76};
double * ptr_score;
ptr_score = score;
for(i=0;i<5; i++)
{
    cout << (void*)ptr_score++ << endl;
}

输出:

0x6dfec0

0x6dfec8

0x6dfed0

0x6dfed8

0x6dfee0

注:一个类型为T的指针的移动,以sizeof(T)为移动单元。因为score是double类型,所以每次移动8个字节空间

 

6.2、指针加上或减去某个整数值

int i;
double score[5] {98, 87, 65, 43, 76};
double * ptr_score;
ptr_score = &score[1];    //取第一个数据的地址
ptr_score +=2;            //取第三个数据的地址
cout << (void*)ptr_score++ << endl;
ptr_score -=3;            //取第一个数据的地址
cout << (void*)ptr_score++ << endl;

结果:

0x6dfed8

0x6dfec8

 

7、数组与指针小结

7.1、一维数组与指针

  • int num[50]; //num是数组名,也可以理解成数组的首地址

  • num的值与&num[0]的值是相同的

  • 数组第i+1个元素可表示为:

第i+1个元素的地址:

&num[i+1]
num+i+1

第i+1个元素的值:

num[i+1]
*(num+i+1)
*++ptr_num
  • 为指向数组的指针赋值:

int * ptr_num = num; 
int * ptr_num = &num[0];
  • 指针变量可以指向数组元素

int * ptr_num = &num[4];
int * ptr_num = num + 4;

7.2、二维数值与指针

  • 如5行3列的二维数组指针首地址为&a[0][0]

  • 使用指针访问二维数组元素中的元素

*(a[1]+2);    //表示a[1][2]
*(*(a+1)+2);    //表示a[1][2]

 

example1:

#include <iostream>
using namespace std;

int main()
{
    int * p = new int[10];
    //用指针创建二维数组
    int (*p2)[3] = new int[5][3];//降维操作//第一维已经降维,第二维3不变
    p2[3][2] = 555;    //给其中一个赋值

    for(int i = 0; i<5; i++)
    {
        for(int j=0; j<3; j++)
        {
            //两种输出模式
            //cout << p2[i][j] << ',';    
            cout << *(*(p2+i)+j) << ',';
        }
        cout << endl;
    }
    return 0;
}

输出结果:

9966960,9992840,0,

0,0,0,

0,0,0,

0,0,555,

0,0,0,

 

example2:

#include <iostream>
using namespace std;

int main()
{
    int * p = new int[10];
    //用指针创建二维数组
    int arrays[5][3] ={
    {1,2,3},
    {4,5,6},
    {7,8,9},
    {10,11,12},
    {13,14,15},
    };
    int (*p2)[3] = arrays;
    for(int i = 0; i<5; i++)
    {
        for(int j=0; j<3; j++)
        {
            //两种输出模式
            //cout << p2[i][j] << ',';    
            cout << *(*(p2+i)+j) << ',';
        }
        cout << endl;
    }
    //输出每个元素的地址
    cout << &arrays[1][0] << endl;
    for(int i = 0; i<5; i++)
    {
        cout << p2 + i <<endl;
    }    
    return 0;
}

输出结果:

1,2,3,

4,5,6,

7,8,9,

10,11,12,

13,14,15,

0x6dfeac    //arrays[1][0]输出元素地址

0x6dfea0

0x6dfeac    arrays[1][0]输出元素地址

0x6dfeb8

0x6dfec4

0x6dfed0

 

 

8、动态分配内存

8.1、使用new分配内存

int * p = new int;   //在运行此句话阶段分配未命名的内存
int num;             //此为编译阶段分配内存;

解析:p在栈区,在堆区分配一块int型空间

注:在运行阶段分配未命名的内存以存储值

 

8.2、使用delete释放内存

delete ptr_int;    //释放由new释放的内存

注:

  • 与new配对使用;

  • 不要释放已经释放的内存;

  • 不能释放生命变量分配的内存;

  • 不要创建两个指向同一内存块的指针,有可能误删除两次。

example:

#include <iostream>
using namespace std;

int main()
{
    int num[5];//分配了20字节的空间,即使空间里面没有数值;
    int* nums = new int[5]; //运行到这一步才在堆内存分配5个字节的整形空间,nums表明空间的地址大小
    cout << sizeof(num) << ''\t' <<sizeof(nums) <<endl
}

运行结果:20    4

 

9、动态分配数组

9.1、使用new创建动态分配的数组

int * intArray = new int[10];

注:new运算符返回第一个元素的地址

9.2、使用delete[]释放内存

delete [] intArray;//释放整个数组

example:

int * ptr_int = new_int;
short * ptr_short = new short[500];
delete ptr_int;        //释放由new释放的内存
delete [] ptr_short;//释放整个数组

注:关于new和delete使用的规则:

  • 不要使用delete释放不是new分配的内存

  • 不要使用delete释放统一内存两次

  • 如果使用new[]释放为数组分配内存,则对应delete[]释放内存

 

9.3、程序的内存分配

  • 栈区(stack):由编译器自动分配释放,一般存放函数的参数值,局部变量的值等。其操作方式类似数据结构中的栈-先进后出。

  • 堆区(heap):一般由程序员分配释放,若程序不释放,程序结束时可能由操作系统回收。其数据结构中的堆是两回事,分配方式类似链表。

  • 全局区(静态区-static):全局变量和静态变量是存储在一起的,程序结束后由系统回收。

  • 文字常量区:常量符号串就放在这里,程序结束由系统回收。

string a="hello,world!";
  • 程序代码区:存放函数体的二进制代码。

注:

#include <iostream>
using namespace std;
int num1 = 0;
int * ptr1;
int main 
{
    int num2;        //栈区
    char str[] = "hello,world!";//栈区
    char * ptr2;            //栈区
    char * ptr3 = "hello,world!"; //hello,world!以及\0在常量区,ptr3在栈区
    static int num3 = 1024;    //全局(静态)初始化区
    ptr1 = new int[10];        //分配的内存在堆区
    ptr2 = new char[20];
    //注意:ptr1和ptr2本身在栈区
    return 0;
}

 

10、总结

1、指针是一个变量,存储另一个变量(对象)的内存地址

2、指针的声明由基本类型、星号(*)和变量名组成

3、为指针赋值,赋值运算符号右侧必须是一个地址

  • 如果是普通变量需要在前面加一个取地址运算符&

  • 如果是另一个指针变量或者是一个数组,不需要加&运算符

4、运算符*用于返回指针指向的内存地址中存储的值

5、使用指针访问一维数组和二维数组的元素

int num = 4;
int* p_num = &num;//取num所在的地址值
*p_num = 112;    //指向num的值变为112
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值