精华内容
下载资源
问答
  • 数组做函数参数:在传递过程中,传递的是实参中每个元素的拷贝,如果实参数组较大,效率比较低 package main import "fmt" //数组作为函数的参数,是进行值传递 //实参数组的每一个元素,在传递的时候...

    一、数组做函数参数   

    • 数组做函数参数:在传递过程中,传递的是实参中每个元素的拷贝,如果实参数组较大,效率比较低
    package main
    
    import "fmt"
    
    //数组作为函数的参数,是进行值传递
    //实参数组的每一个元素,在传递的时候,都给形参拷贝一份,因此当实参数组较大,效率就比较低
    //简而言之:形参数组是实参数组的复制品
    func transferAndModify(arr [5]int) {
    	arr[0] = 111
    	fmt.Println("modify:arr=", arr)  //modify:arr= [111 5 3 9 10]
    }
    
    func main() {
    	// 定义一个数组
    	arr := [5]int{1, 5, 3, 9, 10}
    	// 定义一个函数
    	transferAndModify(arr) // 值传递
    	fmt.Println("main:arr=", arr)   //main:arr= [1 5 3 9 10]
    }
    

    二、数组指针做函数的参数

    •    数组的指针做函数的参数:传递实参的内存地址,指向实参的内存
    package main
    
    import "fmt"
    
    //p指向实参数组arr,p就是数组arr的指针
    //*p代表指针所指向的内存,就是实参arr
    
    func transferAndModify(p *[5]int) {
    	(*p)[0] = 111
    	fmt.Println("transferAndModify:*p=", *p)  //transferAndModify:*p= [111 5 3 9 10]
    }
    
    func main() {
    	// 定义一个数组
    	arr := [5]int{1, 5, 3, 9, 10}
    	// 定义一个函数
    	transferAndModify(&arr) //地址传递
    	fmt.Println("main:arr=", arr)  //main:arr= [111 5 3 9 10]
    }
    

     

    展开全文
  • 从PHP函数参数为数组和对象的区别说开去 ...函数参数为数组和对象的区别 变量的底层结构 对象的底层结构 *HashTable —PHP的灵魂 函数参数为数组和对象的区别 先写一个不算很好的例子但是足够说明问题了。...

    从PHP函数参数为数组和对象的区别说开去

    从PHP函数形式参数为数组和对象的区别说开去,首先比较一下函数的参数为数组和对象的区别,然后由此说开,谈谈变量的底层结构,对象的底层结构,hashTable的底层结构。

    • 函数参数为数组和对象的区别
    • 变量的底层结构
    • 对象的底层结构
    • *HashTable —PHP的灵魂

    这里写图片描述

    函数参数为数组和对象的区别

    先写一个不算很好的例子但是足够说明问题了。

    这里写图片描述

    class Test {
       public $b = 0;
    
    }
    
    function change( $a   )
    {
        if(is_array($a)  ){
    
           $a['a'] = 1;
        }else{
           $a->b= 1;
        }
        return $a ;
    }
    
    $array = [ 1, 2, 3,'a'=>2];
    $b = new  Test();
    var_dump(($array));
    echo 'up array dowm class ';
    var_dump(($b));
    echo 'no cchange  ';
    change($array);
    var_dump($array);
    echo 'up array dowm class ';
    change($b);
    var_dump(($b));
    
    

    打印结果如下:

    array(4) {
     [0]=>
     int(1)
     [1]=>
     int(2)
     [2]=>
     int(3)
     ["a"]=>
     int(2)
    }
    up array dowm class object(Test)#1 (1) {
     ["b"]=>
     int(0)
    }
    no cchange  array(4) {
     [0]=>
     int(1)
     [1]=>
     int(2)
     [2]=>
     int(3)
     ["a"]=>
     int(2)
    }
    up array dowm class object(Test)#1 (1) {
     ["b"]=>
     int(1)
    }

    数组在函数中被改变了,但是并不影响原本的数组,这说明数组的传递是一个值传递(副本),而对象的传递是引用传递所以函数中改变了对象的属性,所以原本的对象也被改变了。而且据说“因为php内置函数默认就是传的值而不是引用”。笔者目前没有看见任何资料上有这句话,又看到的朋友欢迎留言指证。很明显上面的例子说明了问题,不管对象的传递默认是传值还是传引用对对象来说都变了。

    点击链接进入页面可以看到:“因为php内置函数默认就是传的值而不是引用”。 在array_map函数讲解那块!!!—— 重剑无锋 大巧不工

    变量有作用的存在就没有这个问题了,这里不再赘述。

    变量的底层结构

    都知道PHP内核是C写的。
    下面根据PHP变量的结构开始介绍一系列PHP底层的C代码。
    变量是PHP的源泉。笔者认为的!!!

    因为数组是一种变量,而对象也是一种变量。—— PHP核心技术与最佳实践第四页

    变量的结构C代码如下:

    typedef struct _zvalue_value{
    long lval;// 存放long、bool和resource
    double dval;
    struct {
        char *val;
        int len;
    }str;
     HashTable   * ht;// 本文后面会讲
     zend_object_value obj;
    
    }zvalue_value;

    值得注意的是所有变量的底层类型都是zvalue_value。
    看到这里大家似乎有点理解为什么PHP中变量可以存储各种类型了。
    别急,变量还需要一个结构去存储引用等信息,也就是有名的zval结构体。

    struct _zval_struct{
    zvalue_value val;// 存放PHP变量的值
    zend_uint refcount; // 变量引用计数
    zend_uchar is_ref; // 变量是否被引用
    zend_uchar type; // 变量的类型
    }zval_struct;
    
    typedef _zval_struct zval;

    结构体重的type的取值如下表

    PHP类型
    IS_NULL0NULL
    IS_LONG1整数
    IS_DOUBLE2浮点
    IS_STRING3字符串
    IS_ARRAY4数组
    IS_OBJECT5对象
    IS_BOOL6布尔
    IS_RESOURCE7资源(句柄)

    这里写图片描述

    zval结构体是PHP变量在内核中表示方式。—— PHP核心技术与最佳实践第260页

    
     $a = 1;
    $b = '0';
    var_dump($a);
    var_dump($b);
    $a = $b ; 
    var_dump($a);
    
    $a = (int) $b ; 
    var_dump($a);
    

    打印如下:

    int(1)
    string(1) "0"
    string(1) "0"
    int(0)
    

    PHP变量有一个节省内存的方案:写时复制

    也就是在变量赋值给另一个变量时并不会马上分配一个新的内存块,而是当这2个变量不一样时(其中有人变化了),才会重新分配一块内存去单独存放(内存的复制)。

    //比如 
    $a =2;
    $a = $b;
    // 此时$a$b相同,都指向一块相同的内存块,没有分配一个多余的内存块去
    // 单独存放$a或者$b,下面改变$b
    $b = 1;// 此时发现$b变化了,在分配一块内存去存放$b

    对象的底层结构

    对象的底层由属性数组和方法数组共同组成。
    这里写图片描述

    对象在zend引擎中的定义如下:

    typedef struct _zend_object {
    zend_class_entry *ce; // 类指针
    HashTable  * properties;// 对象的属性
    HashTable * guards; // 阻止递归调用
    }zend_object;

    值得注意的是,根据_zend_object结构体可以看到对象的属性和类指针是2个指针,也就是说一个类的对象和它的属性是分开了。
    怎么说?解释一下:加入$a 是类test的对象,那么ce指针指向test类,也就是test类有的对象a都有,而对象特有的(比如动态创建的成员属性或者方法)在properties指针中,而不在ce指针中,这就导致了说为什么PHP对象可以动态创建成员。

    class tests {
    
        public $a = '123';
    
    } 
    echo "class";
    $a = new tests();
    var_dump(new tests());
    var_dump($a);
    $a->b = 'abf';
    echo "class";
    var_dump(new tests());
    var_dump($a);
    
    

    打印如下:

    classobject(tests)#2 (1) {
     ["a"]=>
     string(3) "123"
    }
    object(tests)#1 (1) {
     ["a"]=>
     string(3) "123"
    }
    classobject(tests)#2 (1) {
     ["a"]=>
     string(3) "123"
    }
    object(tests)#1 (2) {
     ["a"]=>
     string(3) "123"
     ["b"]=>
     string(3) "abf"
    }
    
    

    这个例子完美的证明了,当给对象动态创建成员属性时,并不影响类。当再次实例化类时,新的对象并没有以前对象动态创建的属性。精髓就在指针properties上。
    指针ce也是对象与数组的区别的显著特征。对象有一个指向所属类的指针,而数组没有。

    HashTable —PHP的灵魂

    HashTable由HashTable和Bucket组成。为了不弄混,也为了不让读者蒙圈笔者尽量换个角度解释HashTable,尽量浅显易懂一点。

    这里写图片描述

    HashTable数据结构由2部分组成,它本身和外部的一个叫Bucket的结构体。
    先看完整的HashTable结构体定义。

    typedef  struct _hashtable {
    uint nTableSize;// 记录Bucket数组的大小
    uint nTableMask; // 等于nTableSize-1
    uint nNumberOfElements;// 记录HashTable中元素的个数
    ulong nNextFreeElement;// 下一个可用Bucket位置
    Bucket * pInternalPointer;// 遍历HashTable元素
    Bucket * pListHead;// 双链表表头
    Bucket * pListTail;// 双链表表尾
    Bucket * * arBuckets;// Bucket数组
    dtor_func_t pDestructor;// pDestructor
    zend_bool persistent;// persistent,是否使用PHP的内存管理默认是否则使用操作系统
    unsigned char nApplyCount;// 0
    zend_bool bApplyProtection;// 1
    }HashTable;
    
    // Bucket
    typedef struct  bucket{
    ulong h;// hash之后的hash值
    uint  nKeyLength;// 索引的长度
    void  *pData;// 保存的内存块地址
    void  *pDataPtr;// 指针数据
    struct  bucket *pListNext; // 指向双向链表的下一个元素 
    struct  bucket *pListLast;// 指向双向链表的上一个元素
    struct  bucket *pNext;// 指向相同hash值的下一个元素--拉链法
    struct  bucket *pLast;// 指向相同hash值的上一个元素--拉链法
    char    arKey[1]; // 保存索引,而且必须是最后一个成员???
    }Bucket;
    

    这里说明以下几点:
    1 hashtable之所以维护双向链表是为了有序遍历hashtable中的元素;
    2 nTableSize的大小不是PHP实际申请的内存的大小,PHP申请的内存大小是不小于nSize的2的n次方。比如要求申请7 那么 申请的大小是 2^n = 8>=7;
    3 最好使用PHP的内存管理,操作系统去管理内存容易造成内存泄漏,persistent设置为true;

    下面分析hashtable的插入过程:
    1 申请内存(Bucket结构体保存索引和值);
    2 索引复制到arkey中;
    3 pData指向值;
    4 把新Bucket添加具有相同hash值的双向链表中,没有就是该双向链表的第一个元素(主要通过宏 CONNECT_TO_BUCKET_DLLIST完成);
    5 把新Bucket添加到Hashtable双向链表中(通过CONNECT_TO_GLOBAL_DLLIST宏完成);
    6 插入完成后,进行统计,如果HashTable元素的个数大于arBuckets数组的大小(nNumOfElements大于nTableSize),将hashtable的arBuckets数组大小翻倍,始终保持nNumOfElements小于nTableSize。

    以上是个人总结和读书笔记整理而来,有些地方可能有笔误望指正!!!
    这里写图片描述

    留个随堂练习:请问hashtable中有几个双向链表?

    展开全文
  • 1、指针函数参数 指针做形参,我们调用函数将实参传递给形参后,实参和形参指向相同的内存地址。也就是说、被调函中对形参的改变影响主调函数中的实参所指对象。 指针函数参数的作用: a、和引用一样,达到...
    1、指针做函数参数
    	指针做形参,我们调用函数将实参传递给形参后,实参和形参指向相同的内存地址。也就是说、被调函数中对形参的改变影响主调函数中的实参所指对象。
    指针做函数参数的作用:
    	a、和引用一样,达到数据双向传递的效果。
    	b、减少参数传递的开销(引用也一样)
    	c、可以通过指向函数的指针传递函数代码的首地址
    
    #include<iostream>
    using namespace std;
    void swap(int* a,int* b);
    int main()
    {
             inti=1,j=2;
             swap(i,j);
             cout<<i<<""<<j<<endl;  //i=2,j=1
             //很明显i,j的值在主调函数中改变了
             return0;
    }
    void swap(int* a,int* b)
    {
             inttmp=*a;
             *a=*b;
             *b=tmp;
    }
    2、指针函数
    除void之外,函数都有自己的返回值。同样指针也可以作为返回值。
    返回值是指针的函数我们称之为“指针函数”,普通函数只能返回一个变量或对象。
    指针型函数好处是可以在函数结束调用时将大量数据从被调函数返回到主调函数
    (当然这里需要注意的是不能返回局部变量的地址)
     
    3、函数指针
    我们知道程序运行时,数据会占用内存空间。
    实际上代码也会调入内存并占用内存空间。函数名就是函数代码占用内存的首地址
    这样函数指针就是存放函数代码首地址的变量。
    声明形式:
    数据类型 (*函数指针名)(形参列表) 
    //注意指针名的括号,如果没有括号就是指针函数了
    函数指针名=函数名;
    #include<iostream>
    using namespace std;
    void swap1(int* a,int* b);
    void (*funPoint)(int*,int*);  //函数指针,且返回值类型、形参个数、类型都必须匹配
    int main()
    {
             inti=1,j=2;
             funPoint=swap1;
    //      swap1(&i,&j);
             funPoint(&i,&j);//通过函数指针调用
             cout<<i<<""<<j<<endl;  //i=2,j=1
             return0;
    }
    void swap1(int* a,int* b)   //该函数最好不要定义为swap,不然可能调用内置的swap函数模板
    {
             inttmp=*a;
             *a=*b;
             *b=tmp;
    }



     
    展开全文
  • 指针函数形参时,我们调用此函数将实参值传递给形参后,实参和形参指针变量将指向相同的内存地址,那么在被调函中对形参指针所指向的对象的改变会一样影响主调函数中实参指针指向的对象。  指针用作函数参数...

        转载自:http://www.jizhuomi.com/software/82.html

     1 指针用作函数参数

           以前我们学过的函数参数要么是基本数据类型的变量,要么是类的对象,又或者是数组名,前几讲学到的指针同样可以用作函数参数。指针作函数形参时,我们调用此函数将实参值传递给形参后,实参和形参指针变量将指向相同的内存地址,那么在被调函数中对形参指针所指向的对象的改变会一样影响主调函数中实参指针指向的对象。

        指针用作函数参数用什么作用呢?其一,使形参指针和实参指针指向相同的内存地址,在被调函数中可以使用主调函数中的数据并可以改变主调函数中的数据,达到数据双向传递的效果。当然,前面讲过的引用也可以实现相同的作用。其二,用指针作函数参数传递数据可以减少参数传递的开销,引用当然也可以实现这些。其三,可以通过指向函数的指针来传递函数代码的首地址。

        指针和引用很多时候作用是一样的,引用相对指针来说可读性更好,但有时还是需要使用指针。

     #include<iostream>
           using namespace std;
           void Swap(int *a, int *b);
           int _tmain(int argc, _TCHAR* argv[])
           { 
                     int x=5, y=10;
                     cout<<"x="<<x<<"    y="<<y<<endl;
                     Swap(&x, &y);
                     cout<<"x="<<x<<"    y="<<y<<endl;
                     return 0;
           }
           void Swap(int *a, int *b)
           { 
                     int t;
                     t=*a;
                     *a=*b;
                     *b=t;
           }   

         这里的Swap函数使用了指针作为参数,我们在调用时传入的是x和y的地址,分别传递给了a和b,然后在Swap内部改变了a和b指向的变量的值,而实际上它们指向的就是x和y,所以x和y的值发生了同样的改变。程序运行结果依然是:

           x=5    y=10
           x=10    y=5

    2 指针型函数

           函数都有自己的类型,除void类型的函数外都有自己的返回值。函数的返回值也可以是指针。返回值为指针类型的函数就是指针型函数。普通函数只能返回一个变量或对象,但指针型的函数可以在函数调用结束时将大量数据从被调函数返回到主调函数中,这就是它的好处。 注意不要返回局部变量的地址,因为出了被调函数局部变量就释放了,返回的地址中存放的内容也是无效的了。
           声明指针型函数的语法形式是:
           数据类型 *函数名(参数表)
           {
                    函数体
           }
          数据类型指明了函数返回的指针的类型,“*”和函数名说明这是一个指针型函数,参数表是函数的形参列表。

    3 函数指针

          我们知道,程序运行时,数据会占用内存空间,实际上程序执行时代码也会调入内存,也会占用内存空间。函数名就是函数代码占用内存空间的首地址。函数指针就是用于存放函数代码首地址的变量。
          我们也可以使用函数指针来调用函数,它和函数名实现的作用是一样的。声明方式也类似,也需要指明函数的返回值、形参列表,声明的语法形式是:
                     数据类型 (*函数指针名)(形参列表);
          数据类型指明了函数指针所指向函数的返回值类型,函数指针名给出函数指针的名称,形参列表则说明了函数指针所指函数的形参类型和形参个数。
          函数指针和一般的指针一样也要在使用之前先赋值,让它指向一个函数代码的首地址。为函数指针赋值的语法形式是:
                     函数指针名 = 函数名;
          被指向的函数需要是声明过的已存在的,和函数指针必须具有相同的返回值类型、形参个数和形参类型。给函数指针赋值之后我们就可以通过函数指针名来调用它指向的函数了。 
    <span style="font-family:FangSong_GB2312;">   #include <iostream>
            using namespace std;
    
            void show(int x)
            {
                    cout << x << endl;
            }
    
            void (*show_pointer)(int);      // 声明一个void类型的函数指针
    
            int main()
            {
                   int a = 10;
                   show_pointer = show;        // 函数指针show_pointer指向show
                   show_pointer(a);            // 函数指针调用
                   return 0;
            }</span>
        上面例子中声明了一个void类型的函数指针:void (*show_pointer)(int);。我们通过给此函数指针赋值让其指向void类型的函数show,然后用函数指针实现了对函数的调用,输出了a的值。程序运行结果是:10。



    展开全文
  • 指针作为函数参数,可以使被调函通过形参指针存取主调函数中实参指针指向的数据,实现数据的双向传递 需要传递一数据,只传首地址运行效率比较高 实参是数组名时形参可以是指针 指针函数即返回值是使地址...
  • 指针数组 首先从名字就可以知道这是一个数组,是存放指针的数组。 先看几种指针数组: int * 数组指针 函数指针 函数指针数组 指向函数指针数组的指针
  •  指针函数形参时,我们调用此函数将实参值传递给形参后,实参和形参指针变量将指向相同的内存地址,那么在被调函中对形参指针所指向的对象的改变会一样影响主调函数中实参指针指向的对象。  指针用作函数...
  • 详解C语言指针函数函数指针函数指针数组

    万次阅读 多人点赞 2018-07-09 11:08:24
    而在指针中,指针函数函数指针指针函数数组、函数指针数组、指向函数指针数组的指针等等概念看着又绕又头疼。本问总结了一下以上一些概念以及用法,并给出例程深化理解。 1. 指针函数 指针函数就是返回指针值...
  • 指针作为函数参数:为什么需要指针参数: 1. 需要数据双向传递时(引用也可以达到此效果) 2. 需要传递一数据,只传首地址运行效率比较高example:#include &lt;iostream&gt; using namespace std; ...
  • 指向函数指针变量的用途之一就是可以把该函数的入口地址作为参数传递到其它函数(传递给形参)。 原理举例: 有一个函数名为fun的函数,它有两个形参x1和x2,并且定义x1和x2为指向函数指针变量。在调用fun函数...
  • 转自百度知道: 思考:为什么两个运行结果不同 ...C语言使用值传递时,仅仅将实参的值传递给形参。...a所在的地址里面的值,也就是a本身的值了,所以第一种写法main函数调用Swap函数之后,a和b的值会发...
  • 数组的内部指针是数组内部的组织机制,指向一个数组中的某个元素。默认是指向数组中第一个元素通过移动或改变指针的...这些函数参数都是只有一个,就是要操作的数组本身。在下面的示例中,将使用这些数组指针函数控
  • 理解 指针数组 数组指针 函数指针 函数指针数组 指向函数指针数组的指针
  • 指针函数函数指针

    万次阅读 多人点赞 2019-03-30 16:21:36
    很多人因为搞不清这两个概念,干脆就避而远之,我刚接触C语言的时候对这两个概念也比较模糊,特别是当指针函数函数指针函数指针变量、函数指针数组放在一块的时候,能把强迫症的人活活逼疯。 其实如果理解了这些...
  • 就像自定义数据类型一样,我们也可以先定义一个函数指针类型,然后再用这个类型来申明函数指针变量。 我先给你一个自定义数据类型的例子。 typedef int* PINT; //为int* 类型定义了一个PINT的别名 int main() {  ...
  • 的代码量会很大,并且效率会比较低,这个时候就可以使用函数指针数组来解决这个问题了,可以使用每个条件为数组下表:如下所示: 结果如下     回调函数   1、基础知识 所谓回调,就是...
  • 函数参数指针

    2008-09-17 22:14:00
    函数参数可以是指针 函数参数也可为指针,它的作用是将一个变量的地址传递给被调函数的形参。此时,主调函数的调用点上的实参必须是地址值(指针),而被调函数的形参一定要定义成指针变量的形式,只有这样才能...
  • 就像自定义数据类型一样,我们也可以先定义一个函数指针类型,然后再用这个类型来申明函数指针变量。 我先给你一个自定义数据类型的例子。 typedef int* PINT; //为int* 类型定义了一个PINT的别名 int main
  • 指针作为函数参数 1. 函数参数概念:  形参:被调函中的参数  实参:主调函数中的参数  形参和实参:  C 中函数中实参和形参是按值传递的,调用函数后,会将实参的值拷贝给形参(即形参和实参之间是没有...
  • 函数指针函数指针类型

    千次阅读 2018-09-29 08:48:59
    每一个函数都占用一段内存单元,它们有一个起始地址,指向函数入口地址的指针称为函数指针。 注意:函数指针的本质是一个指针变量,且指针指向的函数的入口地址 2. 语法 指向函数指针变量的一般定义形式为: ...
  • C语言函数指针函数参数案例

    千次阅读 2013-10-09 12:38:01
    本案例利用函数指针当作函数参数函数 add(int (*pf)(int*,int),int *a,int n)可以做到传入addOne就对数组a中每个数值加1,传入addTwo就对数组a中每个数值加2,案件具体代码如下: #include //对数每个数加...
  • 函数指针函数指针数组,函数指针数组的指针

    千次阅读 多人点赞 2017-11-27 11:39:51
    数组指针 概念:数组指针指针,只要是指针他就占4个字节; 例如: 整形指针:int *p;能够指向整形数据的指针  浮点型指针:float *p;能够指向浮点型的数据的指针 那么数组指针,同样的理解就是指向数组的指针...
  • 指针数组表达式为:int *p[5] 理解:下标运算符[ ]的优先级是要高于指针运算符*,因此p先和下标运算符结合,决定了p首先是个数组,其类型int *,表明数组的元素都是都是指针。而数组占多少个字节由数组本身决定。...
  • 如何正确使用指针(指针作为输出型参数)与结构体指针作为函数参数 外部定义一个结构体类型指针变量,使用##结构体指针里面的内嵌指针,返回值,双重指针##方式进行地址传递
  • 只要在参数声明中声明是相同参数、类型和相同返回类型的函数指针int (*p)(int),传递时只需传函数名就可以了. 可是传递成员函数指针用此方法却不能工作。指针是指向一些内存地址的变量,既可以是数据的地址也...
  • 概论 指针基础 指针进阶 一维数组的定义与初始化 指针和数 ...在本教程中,我总结了一些关于指针和数的用法(尤其是指针和二维数组)。 2.指针基础 指针是指向另外一种类型的复合类型。 指针本身
  • 例如,可以编写将另一个函数的地址作为参数函数,这样第一个函数将能够找到第二个函数,并运行它。与直接调用另一个函数相比,这种方法显得很笨重,但它允许在不同的时间传递不同函数的地址,这意味着可以在不同的...
  • /指针数组 示例:char *a[4] 理解:定义了一个数组,而它的每个元素的类型是一个指向字符/字符串的指针。 元素表示:char *a[i] char *(a[i])是一样的,因为[]优先级高于* 思考:是否可以这样理解 (char*)arr...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 651,855
精华内容 260,742
关键字:

函数参数为数组指针