当一个函数被调用时,参数被计算并且每个参数都被分配了相应参数的值。
例如,您可以想象函数 revstr 的定义及其在 main 中的调用方式如下(为了清楚起见,我将函数参数重命名为 F_A 和 F_l)
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr(A,l);
//...
void revstr( /*char F_A[], int F_l */ )
{
char F_A[] = A;
int F_l = l;
//...
即函数参数由参数表达式的值初始化。
但是这里有个问题。在此声明中
char F_A[] = A;
我们正在尝试使用类似的数组指示符初始化一个数组
char A[] = "Hello";
char F_A[] = A;
这样的初始化是不正确的。您可以使用字符串文字或初始化器的花括号列表来初始化字符数组。
那么这个问题在 C 中是如何解决的呢?
首先,编译器将具有数组类型的函数参数调整为指向数组元素类型的指针。因此这个函数声明
void revstr(char A[], int l);
被编译器调整为声明
void revstr(char *A, int l);
并且两个声明都声明了相同的一个函数。您可以在程序中包含函数的两个声明,尽管编译器会发出一条消息,指出存在冗余函数声明。
另一方面,当数组用作参数表达式时,它也会隐式转换为指向其第一个元素的指针。
其实你有
void revstr( char *A, int l );
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr( &A[0], l );
//...
因此,在函数中,您正在处理一个指针,该指针指向在 main 中声明的数组 A 的元素所在的内存范围。使用此指针,您正在更改这些元素,即 main 中声明的原始数组。
实际上数组A 的元素是通过指向它们的指针传递给函数的。这种在 C 中通过指向对象的指针来传递对象称为通过引用传递。使用指针,您可以直接访问指针所指向的对象。
注意,函数revstr的声明和定义最好如下面的演示程序所示。
#include <stdio.h>
#include <string.h>
char * revstr( char *s, size_t n )
{
if ( n != 0 )
{
for ( size_t i = 0; i < --n; i++ )
{
char c = s[i];
s[i] = s[n];
s[n] = c;
}
}
return s;
}
int main(void)
{
char s[20];
scanf( "%19s", s );
size_t n = strlen( s );
puts( revstr( s, n ) );
return 0;
}
程序输出可能看起来像
Stackoverflow
wolfrevokcatS
即函数revstr的第二个参数应该是size_t类型而不是int类型,因为size_t是函数strlen的返回类型。
函数应该返回指向反向数组第一个字符的指针。