2010/11/8

2010/11/8

关键字:函数

函数零散知识点

通常函数不应该有vector和其他标准库容器类型的形参.调用含有普通的非引用vector形参的函数会复制vector中的每一个元素.

有两种方法避免,将形参改为引用类型或将需要处理的迭代器作为形参来传递容器.

数组做形参

1.      数组有两个特性,一是不能复制数组,二是使用数组名字时,数组名会自动转换为指向其第一个元素的指针.虽然不能直接传递数组,但是函数的形参可以写成数组的形式.下面三种定义是等价的:

void func1(char* array){}

void func2(char array[]){}

void func3(char array[10]){} //编译器会忽略数组大小

编译器会忽略任何数组形参指定的长度,根据数组的长度可以写出下面的函数:

void func3(char array[10])       //编译器会忽略数组大小

{

        for (int i=0; i<10; ++i)

        {

            array[i] += 1;

        }

}

 

int _tmain(int argc, _TCHAR* argv[])

{

        char array[2] = {0, 1};

        func3(array);               //编译通过,但是调用时会有问题

        return 0;

}

函数假定所传递的数组至少含有10个元素,但是C++没有任何机制强制实现这个假设.

可靠的方法是用另一个参数传递数组的大小.

非引用数组形参,编译器只检测实参和形参是否具有相同的类型,而不会去检查实参实际上是否指向指定大小的数组.

2.      引用类型的数组做形参时,编译器会传递数组引用本身作为实参,会严格要求数组形参和实参的大小一致.

        void func3(char (&array)[10])

{

        for (int i=0; i<10; ++i)

        {

            array[i] += 1;

        }

}

 

int _tmain(int argc, _TCHAR* argv[])

{

        char array[2] = {0, 1};

        func3(array);           //编译失败

        char array1[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

        func3(array1);          //编译ok,运行ok

        return 0;

}

char (&array)[10]中的()是必须的,因为[]操作优先级比&.

char &array[10],是引用的数组,char (&array)[10]是数组的引用.

3.      同理,多维数组做参数时下面三种也是相同的:

        void func3(char (*array)[10]){}

void func4(char array[][10]){}

void func5(char array[10][10]){}    //第一个会被忽略

void func3(char (*array)[10]){}中的()是必须的,因为*[]优先级要低,

char *array[10]表示arraychar*类型指针的数组,实际等效于char [10][],

char (*array)[10]char[10]类型的指针,实际等效于char [][10].

同样,多维数组的引用和数组的引用声明、使用等方式相同.

char (&array)[10][10],表示char[10][10]类型的引用,

char &array[10][10],表示引用的数组的数组.

编译器会检查实参的数组大小是否和形参相同.

void func5(char (&array)[2][2]){}

 

int _tmain(int argc, _TCHAR* argv[])

{

        char array[2][2] = {1, 2, 4, 5};

        char array2[2][3] = {1, 2, 4, 5};

        func5(array);   //ok

        func5(array2);  //error

        return 0;

}

含有可变形参的函数

C++中的省略符形参是为了编译使用了varargsC语言程序.省略符暂停了类型检查机制.因此无法检测实参的个数和类型是否正确.需要程序员自己保证.否则可能会导致运行时错误.

用法形如:

int Func(char *pText, ...)

{

    char buffer[1024]; // working buffer

 

    va_list arglist; // variable argument list

 

    // make sure both the error file and string are valid

    if (!pText)

        return FAIL;

 

    // print out the string using the variable number of arguments on stack

    va_start(arglist,pText);

    vsprintf(buffer,pText,arglist);

    va_end(arglist);

 

    //操作buffer

}

VC8中相关定义

typedef char *  va_list;

#define va_start _crt_va_start

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

#define _ADDRESSOF(v)   ( &reinterpret_cast<const char &>(v) )

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_arg _crt_va_arg

#define va_end _crt_va_end

#define _crt_va_end(ap)      ( ap = (va_list)0 )

 

函数入栈顺序,从内存自高位到低位:

倒数第一个参数              内存地址高位

倒数第二个

第一个参数                       pText的地址

函数返回地址

函数代码                                     内存地址低位

 

其中va_start的作用是获取第二个参数(本例中pText之后的参数)的地址,然后根据参数的类型依次获取剩余的参数值.而参数类型可以在pText中找到.printf(“%s, %d”, ”124”, 2);而使用vsprintf(buffer,pText,arglist);则避免了自己读取每个参数的麻烦.最后va_end会将指针置为0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值