首先强调的是:
C语言中所有函数调用都是传值调用
(数组是例外情况。C里数组名就表示了数组的首地址当把数组名当参数传递时,其实也就是传了个地址而已)
1、传值调用时是copy一份传给函数,在函数体内对传给函数的变量做修改不会影响原变量。这种方法如果传的对象比较大会增加很多的内存开销。
# include < stdio. h> void * fun( char * a) { a= "zerk" ; return ; } int main( void ) { char * s= NULL ; printf ( "----------/n" ) ; fun( s) ; printf ( "%s/n" , s) ; } 输出:. / a. out - - - - - - - - - - ( null )
2、传引用调用实际上是把变量的地址传给函数,所以程序的效率比较高。如果你想返回对变量的修改值,必须用“指向指针”的指针做为函数的参数。
#include < stdio. h> void * fun( char * * a) { * a= "zerk" ; return; }int main( void) { char * s= NULL; printf( "----------/n" ) ; fun( & s) ; printf( "%s/n" , s) ; } 输出:. / a. out - - - - - - - - - - zerk
下面通过对一个取得当前时间的函数的实现的改造过程来说明:
1 实参:一级指针 形参:一级指针 返回类型:int
#include < stdio. h> #include < time. h> int get_datetime( char * buffer ) { struct tm * ptr = NULL ; time_t lt = 0 ; lt = time( NULL) ; ptr = localtime( & lt ) ; strftime( buffer, 15, "%Y%m%d%H%M%S" , ptr ) ; return 1; }int main( void) { char * buf= NULL; get_datetime( buf) ; printf( "[%s]/n" , buf) ; }
输出:
./a.out [(null)]
gdb调试:
Breakpoint 1, main ( ) at time. c: 19 19 char * buf= NULL; ( gdb) s 20 get_datetime( buf) ; ( gdb) s get_datetime ( buffer= 0x0) at time. c: 7 7 struct tm * ptr = NULL ; ( gdb) s 8 time_t lt = 0 ; ( gdb) s 10 lt = time( NULL) ; ( gdb) s 11 ptr = localtime( & lt ) ; ( gdb) s12 strftime( buffer, 15, "%Y%m%d%H%M%S" , ptr ) ; ( gdb) s 13 return 1; ( gdb) p buffer $1 = 0x0 ( gdb) s 14 }( gdb) s main ( ) at time. c: 21 21 printf( "[%s]/n" , buf) ; ( gdb) s[ ( null) ]
2 实参:数组 形参:数组名 返回:int-->验证了数组这一特殊情况
# include < stdio. h> # include < time . h> int get_datetime( char * buffer ) { struct tm * ptr = NULL ; time_t lt = 0 ; lt = time ( NULL ) ; ptr = localtime ( & lt) ; strftime ( buffer, 15, "%Y%m%d%H%M%S" , ptr) ; return 1; } int main( void ) { char buf[ 15] = { 0} ; get_datetime( buf) ; printf ( "[%s]/n" , buf) ; }
输出:/a.out [20071018105321]
gdb调试:
Breakpoint 1, main ( ) at time . c: 19 19 char buf[ 15] = { 0} ; ( gdb) s 20 get_datetime( buf) ; ( gdb) s get_datetime ( buffer= 0xbfffe470 "" ) at time . c: 7 7 struct tm * ptr = NULL ; ( gdb) s 8 time_t lt = 0 ; ( gdb) s 10 lt = time ( NULL ) ; ( gdb) s 11 ptr = localtime ( & lt) ; ( gdb) s 12 strftime ( buffer, 15, "%Y%m%d%H%M%S" , ptr) ; ( gdb) s 13 return 1; ( gdb) p buffer $1 = 0xbfffe470 "20071018105524" ( gdb) s 14 } ( gdb) p buf $2 = 0( gdb) s main ( ) at time . c: 21 21 printf ( "[%s]/n" , buf) ; ( gdb) p buf $3 = "20071018105524" ( gdb) s[ 20071018105524] 22 }
3、调用函数无形参,返回char*型
# include < stdio. h> # include < time . h> char * get_datetime( void ) { char * buffer= NULL ; buffer= ( char * ) malloc ( sizeof ( char ) * 15) ; struct tm * ptr = NULL ; time_t lt = 0 ; lt = time ( NULL ) ; ptr = localtime ( & lt) ; strftime ( buffer, 15, "%Y%m%d%H%M%S" , ptr) ; return buffer; } int main( void ) { char * buf= NULL ; buf= get_datetime( ) ; printf ( "[%s]/n" , buf) ; free ( buf) ; } 输出:. / a. out [ 20071018112403]
容易犯的错误:
#include < stdio. h> #include < time. h> char * get_datetime( void ) { char * buffer= NULL;//buffer为局部变量,调用函数结束后自动释放 // buffer= ( char * ) malloc( sizeof ( char) * 15) ;//函数调用结束后虽然Buffer释放了,但它分配的那块内存依然有效。 struct tm * ptr = NULL ; time_t lt = 0 ; lt = time( NULL) ; ptr = localtime( & lt ) ; strftime( buffer, 15, "%Y%m%d%H%M%S" , ptr ) ; return buffer; }int main( void) { char * buf= NULL; buf= get_datetime( ) ; printf( "[%s]/n" , buf) ; // free( buf) ; } 输出:. / a. out ( NULL)
当调用函数返回一个数组名时-->我们不能这么做
1 #include < stdio. h> 2 #include < time. h>
3 4 5 char * get_datetime( void ) 6 { 7 char buffer[ 15] = { 0}; 8 struct tm * ptr = NULL ; 9 time_t lt = 0 ; 10 11 lt = time( NULL) ; 12 ptr = localtime( & lt ) ; 13 strftime( buffer, 15, "%Y%m%d%H%M%S" , ptr ) ; 14 return buffer; 15 } 16 17 int main( void) 18 { 19 20 char * buf= NULL; 21 buf= get_datetime( ) ; 22 printf( "[%s]/n" , buf) ; 23 }
输出:./a.out [囵B B橍縐?卲?繕?緽? Bp?扛?縯UB]
4、形参实参为二级指针:
# include < stdio. h> # include < time . h> void get_datetime( char * * buffer )//这是一般性的作法 { char * tmp= NULL ; tmp= ( char * ) malloc ( sizeof ( char ) * 15) ; struct tm * ptr = NULL ; time_t lt = 0 ; lt = time ( NULL ) ; ptr = localtime ( & lt) ; strftime ( tmp, 15, "%Y%m%d%H%M%S" , ptr) ; * buffer= tmp; return ; } int main( void ) { char * buf= NULL ; get_datetime( & buf) ; printf ( "[%s]/n" , buf) ; }
输出:./a.out [20071018121352]
cu的scutan有些话值得思考一番:
void fun( int i) { i = i + 10; }int i = 10; fun( i) ; 这种情况下调用了fun之后i的值会变吗? 同样: void fun( char * p) { p = . . . ; } char * p; fun( p) ; 这种情况下, 当然也不会变了啊. 而你可能经常看到的用法是 char c; fun( & c) ; 此时传递的是c的地址, 而后面是对这个地址进行操作, 所以说* * p, 就是针对的改变char * p这种类型的值, 因为传递给这个参数的是一个指针的地址 其实你要传递给函数的不过是一个地址罢了. 通过这个地址修改这个值. 所以: 对于 char c, 指向一个字符类型的指针为char * p; 所以函数参数为这个. 对于 char * p, 指向一个字符类型指针的指针为char * * p, 所以函数参数为char * * p, 而此时则需要将p的地址传递给这个函数作为参数, 所以就是&p. 其实看开了, char , char * , 都是类型, 不要因为有个什么* 号就迷糊了. 需要指向它们的指针, 就相应地加上* 号成为 char * , char * * .