zoukankan      html  css  js  c++  java
  • 指针

    指针:指针本身是一个变量,他的值为另一个变量的内存地址。申明如下: int *dp; 。举个栗子来认识一下指针:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int tempone = 20;
     7     int *temptwo;
     8     
     9     temptwo = &tempone; //获取tempone的地址赋值给temptwo;
    10     
    11     cout << "temptwo = " << temptwo << endl;
    12     printf("*temptwo = %d
    ",*temptwo);
    13 }

    我们看到temptwo是存了tempone的内存地址,*temptwo通过地址访问到了tempone的值。

    值传递、指针传递、引用传递:

    • 值传递:形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
    • 指针传递:形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
    • 引用传递:形参相当于是实参的"别名",对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

    让我们举个栗子:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 void one(int a){a = a + 100;}
     5 void two(int *a){*a = *a + 20;}   //*a 通过地址取到了b的值
     6 void three(int &a){a = a + 30;} //&a 通过b取到了b的地址,然后在地址处进行操作
     7 
     8 int main()
     9 {
    10     int b = 10;
    11     one(b); //值传递,相当于直接把值给形参了
    12     printf("b = %d
    ",b);
    13     
    14     two(&b);//指针传递,传递给形参的是实参的地址,然后根据地址对b进行操作
    15     printf("b = %d
    ",b);
    16     
    17     three(b); //引用传递,函数里取到了b的地址的位置,然后对b进行操作
    18     printf("b = %d
    ",b);
    19 }
    • & 符号的意思是取地址,也就是返回一个对象在内存中的地址。
    • * 符号的意思是取得一个指针所指向的对象。 也就是如果一个指针保存着一个内存地址,那么它就返回在那个地址的对象。
    • 简单点就是:&:取址。* :取值。

    函数指针:函数存放在内存的代码区域内,它们同样有地址.如果我们有一个函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。如: int (*dp)(int x, int y); 

    举个栗子:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int temp(int a)
     5 {
     6     a++;
     7     return a;
     8 }
     9 
    10 int main()
    11 {
    12     int ex = 0;
    13     int (*dp)(int a);   //这里就定义了一个函数指针,这里要求和定义函数的函数头一致
    14     dp = temp; //把temp的地址赋给dp
    15     ex = dp(5);  //通过函数指针找到函数进行计算
    16     printf("ex = %d", ex);
    17     return 0;
    18 }

    结果为: ex = 6 。但我们对于函数指针通常用到把函数指针当参数传递来达到我们的目的。举个栗子:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int temp(int a)
     5 {
     6     a++;
     7     return a;
     8 }
     9 
    10 int student(int (*dp)(int a))
    11 {
    12     int ex = 0;
    13     ex = dp(5);  //通过函数指针找到函数进行计算
    14     printf("ex = %d", ex);
    15     return 0;
    16 }
    17 
    18 int main()
    19 {
    20     int (*dp)(int a);   //这里就定义了一个函数指针,这里要求和定义函数的函数头一致
    21     dp = temp; //把temp的地址赋给dp
    22     student(dp);  //这里把函数指针做为参数传递
    23     return 0;
    24 }

    结果依然为: ex = 6 

    指针的运算:指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。‘栗子在这里:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int array[4] ={1,2,3,4};
     7     int *dp;
     8     dp = array;
     9     int i;
    10     for(i=0;i<4;i++)
    11     {
    12         cout << "第一个数为:"
    13             <<array[i]
    14             <<",他的地址为:"
    15             <<dp
    16             <<endl;
    17         dp++;
    18     }
    19     printf("
    ");
    20     dp = &array[2];
    21     for(i=2;i<4;i++)
    22     {
    23         cout << "第一个数为:"
    24             <<array[i]
    25             <<",他的地址为:"
    26             <<dp
    27             <<endl;
    28         dp--;
    29     }
    30 }

    结果为:

    第一个数为:1,他的地址为:0x7ffce6e13030
    第一个数为:2,他的地址为:0x7ffce6e13034
    第一个数为:3,他的地址为:0x7ffce6e13038
    第一个数为:4,他的地址为:0x7ffce6e1303c
    
    第一个数为:3,他的地址为:0x7ffce6e13038
    第一个数为:4,他的地址为:0x7ffce6e13034

     数组指针和指针数组的区别:https://www.cnblogs.com/mq0036/p/3382732.html 数组指针强调的是指针,他指的是一个数组的指针;指针数组强调的是数组,他指的是一个数组里面的指针元素。

     指向指针的指针:因为指针是个变量,他自己也是有地址的,所以指向指针的指针就是把存有其他变量地址的这个指针变量的地址存到另一指针中。他的申明如下: int **pr; 。举个栗子说明:

     1 #include <iostream>
     2 using namespace std;
     3 
     4  int main()
     5  {
     6      int temp = 0;
     7      int *pr = 0;
     8      int **prr = 0;
     9      
    10      cout << "pr = " <<pr <<endl;
    11      cout << "prr = " <<prr <<endl <<endl;
    12      
    13      pr = &temp;   //得到变量temp的地址
    14      prr = &pr;    //得到指针pr的地址
    15      
    16      cout << "pr = " <<pr <<endl;
    17      cout << "prr = " <<prr <<endl <<endl;
    18  }

     结果: pr = 0 prr = 0 pr = 0x7ffe64e6074c prr = 0x7ffe64e60740 

     指针作为参数传递给函数:我先看个例子(注意:&a 是整个数组的首地址,a是数组首元素的首地址,其值相同但意义不同。):

     1 #include <iostream>
     2 using namespace std;
     3 
     4 void test_one(int *pr)   //指针参数为单个值的时候
     5 {
     6     *pr = 5;
     7 }
     8 
     9 int test_two(int *array)  //指针参数为数组的首地址或者元素的首地址的时候
    10 {
    11     int temp = 0;
    12     temp = array[1];
    13     return temp;
    14 }
    15 
    16 int main()
    17 {
    18     int array[3] = { 10,11,12 };
    19     int pr = 0;
    20     int getvalue = 0;
    21     
    22     test_one(&pr);   //取pr的地址
    23     cout << "pr = " << pr << endl;  
    24 
    25     getvalue = test_two(array);  //取array的首个元素的地址
    26     cout << "getvalue = " << getvalue << endl;
    27     return 0;
    28 }

    结果为: pr = 5    getvalue = 11 

    我发现当传递的参数指针所指向的地址是单个元素的时候不就是我们的指针传递吗,当指向的地址为多个元素的时候不就是数组中的把数组作为参数传递给函数(通过指针方式传递)吗?其实就是的。因为本身数组名是个内存地址,而指针的值也是内存地址。

    指针作为函数的返回值:其实指针作为函数的返回值跟数组作为函数的返回值也是一致的。只不过指针作为返回值时会区分单个元素还是像数组一样的多个元素。我们还是以栗子来说明:

     1 #include <time.h>
     2 #include <iostream>
     3 using namespace std;
     4 
     5 int *temp_one(int x)  //定义一个返回值为指针的函数(单个元素)
     6 {
     7     static int *pr = 0;//c++不允许在函数外返回局部变量的地址,除非定义static变量
     8     int y = x+1;
     9     pr = &y;   //取到参数地址
    10     return pr;  //返回指针
    11 }
    12 
    13 int *temp_two(int *array)    //定义一个返回值类型为指针(多个元素)、参数为指针的函数
    14 {
    15     static int array_temp[10];  //C++不允许在函数外返回局部变量的地址,除非定义为static变量
    16     int i;
    17     srand((int)time(0));  //时间作为随机数的种子
    18     for (i = 0; i<10; i++)
    19     {
    20         array_temp[i] = array[i];  //取到array的前五个值给array_temp
    21         if ( i >= 5 )
    22         {
    23             array_temp[i] = rand() % 100; //把五个随机数给array_temp的后5个值
    24         }
    25     }
    26     return array_temp;  //返回指针
    27 }
    28 
    29 int main()
    30 {
    31     int one = 1;
    32     int *pr;
    33     int *pr_array;
    34     int array[10] = { 1,2,3,4,5 };
    35     pr = temp_one(one);
    36     cout << "*pr = " << *pr << endl;
    37     pr_array = temp_two(array);
    38     for (size_t i = 0; i < 10; i++)
    39     {
    40         cout << "pr_array["<< i << "] = " << pr_array[i] << endl;
    41     }
    42     return 0;
    43 }

     结果为:

    *pr = 2
    pr_array[0] = 1
    pr_array[1] = 2
    pr_array[2] = 3
    pr_array[3] = 4
    pr_array[4] = 5
    pr_array[5] = 48
    pr_array[6] = 38
    pr_array[7] = 13
    pr_array[8] = 80
    pr_array[9] = 92
  • 相关阅读:
    Fedora 14 安装完后的设置 添加源 更新软件
    visual studio NuGet 常用包管理命令
    ubuntu通过cifs-utils访问Windows共享目录
    C# 数据库写入Sql Bulk索引损坏异常问题System.InvalidOperationException: DataTable internal index is corrupted: '4'
    C# IEnumerable to List 的转换
    python 端口扫描
    ubuntu 关闭 phpmyadmin
    zendframework 初始化配置
    zend-form笔记
    DirectX 图形流水线
  • 原文地址:https://www.cnblogs.com/xiaodangxiansheng/p/10908246.html
Copyright © 2011-2022 走看看