通过将数组作为参数传递给函数来增加数组的大小
Increasing the size of an array by passing it as an argument to function
#include<stdio.h>
void fun1(int a[100])
{
a[4]=1;
}
void main()
{
int a[2]={1,2};
fun1(a);
printf("%d",a[4]); // Output 1
}
我知道当我们将数组作为函数参数传递时,数组会退化为指向第一个元素的指针。但是main函数中数组的大小是如何增加的呢?
您不能更改自动数组运行时的大小。
如果你想在运行时选择声明的自动数组的大小,你可以使用(自 c99 起)VLA.
int n;
scanf("%d", &n)
int a[n];
或者如果您确实需要更改数组运行时的大小,则必须在堆上动态分配内存,然后 realloc 缓冲区大小。
int *a = malloc(sizeof(int) * 2);
int *tmp = realloc(a, sizeof(int) * 4);
if (tmp == NULL)
{
// Reallocation failed
}
else
{
a = tmp;
}
正如@DavidBowling 所说,最好在 sizeof 表达式中使用解除引用的标识符而不是类型。在我们的例子中它将是
int *a = malloc(sizeof *a * 2);
int *tmp = realloc(a, sizeof *tmp * 4);
当指针类型发生变化时更容易出错。
根据 C 标准(6.7.6.3 函数声明符(包括原型))
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’, where the type qualifiers (if any)
are those specified within the [ and ] of the array type
derivation....
这意味着在声明中
void fun1(int a[100])
{
a[4]=1;
}
函数参数调整为int *
类型,结果函数实际上具有以下声明
void fun1( int *a )
{
a[4]=1;
}
例如下面的函数声明
void fun1(int a[2]);
void fun1(int a[10]);
void fun1(int a[100]);
声明一个声明看起来像的函数
void fun1(int *a);
另一方面,表达式中使用的数组(例如函数参数)会隐式转换为指向其第一个元素的指针。所以在这个函数调用中,表达式使用数组指示符
fun1(a);
数组指示符 a
被转换为指向其第一个元素的指针,参数表达式的类型为 int *
.
你可以想象这个调用是这样的
{
int *temporary p = a;
fun1( p );
}
所以函数参数的类型是int *
,它是一个指针,对应的参数也是一个指针。该函数不处理数组类型的对象。它处理指针类型的对象。
所以两个数组都没有增加它的大小,并且原始程序有未定义的行为,因为试图访问原始数组之外的内存。
您可以通过输出参数的大小轻松检查函数是否处理指针。例如
void fun1(int a[100])
{
printf( "sizeof( a ) = %zu\n", sizeof( a ) );
a[4]=1;
}
根据使用的系统,输出将等于 4
或 8
。但在任何情况下,它都不会像您预期的那样等于 100 * sizeof( int )
。
#include<stdio.h>
void fun1(int a[100])
{
a[4]=1;
}
void main()
{
int a[2]={1,2};
fun1(a);
printf("%d",a[4]); // Output 1
}
我知道当我们将数组作为函数参数传递时,数组会退化为指向第一个元素的指针。但是main函数中数组的大小是如何增加的呢?
您不能更改自动数组运行时的大小。
如果你想在运行时选择声明的自动数组的大小,你可以使用(自 c99 起)VLA.
int n;
scanf("%d", &n)
int a[n];
或者如果您确实需要更改数组运行时的大小,则必须在堆上动态分配内存,然后 realloc 缓冲区大小。
int *a = malloc(sizeof(int) * 2);
int *tmp = realloc(a, sizeof(int) * 4);
if (tmp == NULL)
{
// Reallocation failed
}
else
{
a = tmp;
}
正如@DavidBowling 所说,最好在 sizeof 表达式中使用解除引用的标识符而不是类型。在我们的例子中它将是
int *a = malloc(sizeof *a * 2);
int *tmp = realloc(a, sizeof *tmp * 4);
当指针类型发生变化时更容易出错。
根据 C 标准(6.7.6.3 函数声明符(包括原型))
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation....
这意味着在声明中
void fun1(int a[100])
{
a[4]=1;
}
函数参数调整为int *
类型,结果函数实际上具有以下声明
void fun1( int *a )
{
a[4]=1;
}
例如下面的函数声明
void fun1(int a[2]);
void fun1(int a[10]);
void fun1(int a[100]);
声明一个声明看起来像的函数
void fun1(int *a);
另一方面,表达式中使用的数组(例如函数参数)会隐式转换为指向其第一个元素的指针。所以在这个函数调用中,表达式使用数组指示符
fun1(a);
数组指示符 a
被转换为指向其第一个元素的指针,参数表达式的类型为 int *
.
你可以想象这个调用是这样的
{
int *temporary p = a;
fun1( p );
}
所以函数参数的类型是int *
,它是一个指针,对应的参数也是一个指针。该函数不处理数组类型的对象。它处理指针类型的对象。
所以两个数组都没有增加它的大小,并且原始程序有未定义的行为,因为试图访问原始数组之外的内存。
您可以通过输出参数的大小轻松检查函数是否处理指针。例如
void fun1(int a[100])
{
printf( "sizeof( a ) = %zu\n", sizeof( a ) );
a[4]=1;
}
根据使用的系统,输出将等于 4
或 8
。但在任何情况下,它都不会像您预期的那样等于 100 * sizeof( int )
。