C++学习条记之指针(基础)

打印 上一主题 下一主题

主题 807|帖子 807|积分 2421

C++学习条记之指针(基础)

   https://www.runoob.com/cplusplus/cpp-pointers.html
  C/C++中的指针内容是早就盛名在外了,固然了,想要随心所欲地使用也是要做很多功课的,先简单相识下吧~
起首,我们需要相识一点内存的概念:
每一个变量都有一个内存位置,而这个变量的内存位置会有地点,通过&可以举行访问

  1. int a = 10;
  2. cout << &a << endl;   // 访问变量地址
复制代码
顺道再复习下数组
  1. int a[10];
  2. cout << &a << " " << &a[0] << endl;   // 数组地址取的就是首个元素的地址,二者含义相同
复制代码

好,明白这点以后,下面进入正题
1、指针是什么?

指针是一个变量,它的值为另一个变量的地点(内存位置的直接地点)
由于它作为一个变量,因此在使用之前也需要举行声明
  1. 类型 *变量名
复制代码


  • 范例:C++ 数据范例
  • *:表明该变量是指针
  • 变量名:合法的标识符
  1. int *ip;   // int类型指针
  2. double *ptr;   // double类型指针
复制代码
:无论是int范例指针、double范例指针,还是其他各种范例的指针,作为指针变量的值,都是一样的,其实质都是内存地点,均为代表内存地点的长的十六进制数
各个范例指针之间唯一的差别是,指针所指向的变量或常量的数据范例差别,也就是对应内存是存放了什么数据范例,这点是差别的
这就好比外卖员去送东西,外卖员去送外卖只关心顾客住在哪(内存地点),无论是屋子里住的是电影明星还是步伐员(指向变量的范例),它只管按照地点把外卖送到就行了
2、使用指针

通常情况下,使用指针只需要三板斧
①定义一个指针变量
②把变量地点赋值给指针
③访问指针变量中可用地点的值

  1. int value = 100;  
  2. int *ptr = &value;   // 将变量地址给指针变量ptr
  3. cout << *ptr << endl;  // 访问指针地址对应的值,使用*
  4. cout << ptr << endl;  // 访问指针的值,为变量地址
复制代码


*的作用为解引用,用于获取该地点对应的内容,即指针指向变量的值
3、空指针

如果指针变量声明的时间,没有确切的地点可以赋值,通常会为指针赋值NULL
被赋值NULL的指针称为空指针
NULL在标准库中定义为0
  1. int *ptr = NULL;
  2. cout << ptr << endl;    // 0
复制代码

在大多数的操纵系统上,步伐不允许访问地点为 0 的内存,由于该内存是操纵系统保留的,表明该指针不指向一个可访问的内存位置
  1. int *ptr = NULL;
  2. cout << ptr << endl;
  3. if (ptr)   // 通常使用类似的方式判断指针可用
  4. {
  5.     // todo
  6. }
复制代码
如果所有未使用的指针都被赋予空值,同时制止使用空指针,就可以防止误用一个未初始化的指针,通常未初始化的变量存有一些垃圾值,导致步伐难以调试
4、指针的算术运算

C++指针实际上是地点,因此可以对指针举行一些算术运算,包括++、--、+、-
指针的算术运算根据指针的范例和巨细决定移动的距离,比如如果是int范例的指针,int所占字节为4字节,即32位,那么指针每移动一个单位,便是4字节


  • 加法运算
    指针当前指向的地点的基础上加n个单位,每个单位由对应指针的范例决定
    在使用指针操纵数组时,经常使用这些指针运算符,数组的范例统一,因而下一个元素正好可以方便地使用指针的加减来寻址
    1. int arr[] = {1, 2, 3, 5, 4};
    2. int *ptr = arr;    // 指向数组首地址
    3. cout << *ptr << endl;
    4. ptr ++;    // 数组下一个元素
    5. cout << *ptr << endl;
    复制代码
    但是需要注意,当使用指针操纵时,要确保指针指向有效的内存区域,否则可能会导致未定义行为或步伐瓦解
    在操纵数组时,尤其要警惕制止指针超出数组的范围
  • 减法运算
    与加法相反,在当前指针指向的地点的基础上减去n个单位
    1. int arr[] = {1, 2, 3, 5, 4};
    2. int *ptr = &arr[1];   // 指向数组第二个元素的地址
    3. cout << *ptr << endl;
    4. ptr --;   // 向前移一位元素
    5. cout << *ptr << endl;
    复制代码
  • 指针与指针间的减法
    两个指针间的元素个数
    1. int arr[] = {1, 2, 3, 5, 4};
    2. int *ptr1 = &arr[1];
    3. int *ptr2 = &arr[3];
    4. cout << ptr2 - ptr1 << endl;    // 相距2个元素
    复制代码
  • 指针与整数间的比较
    可以将指针与整数举行比较运算,常用于判断指针是否指向某个有效的内存位置
    1. int arr[] = {1, 2, 3, 5, 4};
    2. int *ptr1 = &arr[1];
    3. int *ptr2 = &arr[3];
    4. cout << (ptr1 == ptr2) << endl;  // 假,返回0
    5. cout << (ptr1 < ptr2) << endl;   // 真,返回1
    复制代码
   需要注意,在举行关系比较时,指针需要属于同一数组,否则关系比较结果是未定义的
而且,在举行关系比较前,需要确保指针非空,否则也会产生未定义的行为
  5、指针 vs 数组

在C++中,指针和数组是密切相关的,透过表象看本质,终究还是对内存地点的操纵
数组是内存中连续的单位组合而成,因此其中每个元素是同样的范例,这就可以借助于指针在数组上举行运算,由于每一步正好就是一个范例长度,从数组首地点开始根据盘算可以访问其中的各个元素
  1. int arr[] = {1, 2, 3, 5, 4};
  2. int *ptr = arr;
  3. for (int i = 0; i < 5; i++)
  4. {
  5.     cout << *ptr << endl;
  6.     ptr ++;
  7. }
复制代码
然而,两者之间是无法完全画等号的,如果把数组名看做指针,使用*更换内容,是可以的,但是使用++一类的运算来修改,是不可的,由于修改值不会涉及地点的变革,而使用++等运算符,数组的首地点就变了呀,那还不乱套了

看到报错提示,数组名是不可作为左值的,它的地点不可被改变

数组名属于指向数组开头的常量,因而不能重新对其修改,但是其中内容可以更改,也可以采用指针的方式举行访问
  1. *(arr + 2)   // 相当于arr[2] 结果为3
复制代码
6、指针数组

前面学习了数组,如今又相识了一些指针的内容,此时将二者联合一下,便有了指针数组的概念
着实这个比较好理解的,也就是数组的每个元素都是一个指针,指向某个元素的地点
  1. int  arr[] = {1, 3, 9};
  2. int *ptr[3];
  3. for (int i = 0; i < 3; i++)
  4. {
  5.    ptr[i] = &arr[i]; // 取整数的地址
  6. }
  7. for (int i = 0; i < 3; i++)
  8. {
  9.    cout << *ptr[i] << endl;
  10. }
复制代码
在下面这个例子中,也是一个指针数组,看右边知道,每个元素是字符串,下意识反应字符串着实就是字符数组,数组在某种水平上相称于指针,所以意味着,我们可以把每个元素看做字符指针,那么就可以将字符串作为字符指针数组的元素了,这种转换意识还是需要的
  1. const char *ptr[3] = {
  2. "Bob",
  3. "Bill",
  4. "Mike"
  5. };
  6. for (int i = 0; i < 3; i++)
  7. {
  8.    cout << "name=" << ptr[i] << endl;
  9. }
复制代码
7、指向指针的指针

指向指针的指针,听起来好绕的样子,但是带入生活的案例可能好理解一些,指针对应着地点,比方说我想要熟悉甲,但是我不知道他的地点,但我知道乙的地点,乙知道甲的地点,那么我通过乙去找甲,这便是指针的指针,像极了人际关系网

我和乙都是指针,我们掌握的都是地点,而真正需要的东西在甲手里
声明指针的指针需要使用**
  1. int **ptr;
复制代码
看看简单的使用:
  1. int **pptr;
  2. int *ptr;
  3. int value = 100;
  4. ptr = &value;   // 乙知道甲的地址
  5. pptr = &ptr;   // 我知道乙的地址
  6. cout << value << endl;   // 甲手里的100
  7. cout << *ptr << endl;    // 乙找到甲得到100
  8. cout << **pptr << endl;   // 我找到乙,通过乙找到甲得到100
复制代码
8、传递指针给函数

C++ 允许传递指针给函数,只需要简单地声明函数参数为指针范例即可
  1. int getSum(int *arr, int size) {
  2.     int sum = 0;
  3.     for (int i = 0; i < size; i++)
  4.     {
  5.         sum += arr[i];
  6.     }
  7.     return sum;
  8. }
  9. int main()
  10. {
  11.    int arr[] = {1, 2, 3, 4, 5};
  12.    cout << getSum(arr, 5) << endl;
  13. }
复制代码
9、从函数返回指针

C++ 不支持在函数外返回局部变量的地点,除非定义局部变量为 static 变量
  1. int *getArray( )
  2. {
  3.   static int  arr[3] = {1, 2, 3};   // 局部变量必须是static
  4.   return arr;
  5. }
  6. int main ()
  7. {
  8.    int *p;
  9.    p = getArray();
  10.    for ( int i = 0; i < 3; i++ )
  11.    {
  12.        cout << *(p + i) << endl;
  13.    }
  14.    return 0;
  15. }
复制代码
使用static是为了防止局部变量在函数结束的时间失效,随函数一同出栈,使用static会将该变量放到全局区,即使方法栈结束变量依然有效
先看这么多,估计够消化一阵子了,其余的在实践中慢慢学吧~~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

耶耶耶耶耶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表