为什么在C语言中将一个包含4个元素的数组传递给函数时会出现警告?

huangapple go评论57阅读模式
英文:

Why does a warning appear when passing a 4-element array to a function in C?

问题

当数组大小为4时,将该数组的值传递给函数时为什么会出现警告?

我得到以下警告消息:

<source>: 在函数 'main' 中:
<source>:20:19: 警告: 从整数传递给 'greatestOf' 的参数 1 会造成指针无法转换 [-Wint-conversion]
   20 |     greatestOf(arr[4], &amp;x); // 这里是警告文本。当我尝试使用 'greatest(arr, &amp;x)' 时
      |                ~~~^~~
      |                   |
      |                   int
<source>:4:21: 注意: 期望的是 'int *',但参数的类型是 'int'
    4 | void greatestOf(int arr[], int *result) {
      |                 ~~~~^~~~~

我希望警告文本消失,我认为如果要将值传递给函数,我必须包括数组的大小。因为我想要发送整个值。

英文:

If there is an array with size 4, when the value of that array is sent to a function. Why does a warning appear?

#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

void greatestOf(int arr[], int *result) {
    *result = arr[0];

    for (int i = 1; i &lt; 4; i++) {
        if (arr[i] &gt; *result) {
            *result = arr[i];
        }
    }
}


int main() {
    int arr[4], x;
    printf(&quot;Input : &quot;);
    scanf(&quot;%d %d %d %d&quot;, &amp;arr[0], &amp;arr[1], &amp;arr[2], &amp;arr[3]);

    greatestOf(arr[4], &amp;x); // here warning text. When I try to use &#39;&#39;&#39;greatest(arr, &amp;x)&#39;&#39;&#39;

    printf(&quot;Greatest number: %d\n&quot;, x);

    return 0;
}

I get the following warning message:

&lt;source&gt;: In function &#39;main&#39;:
&lt;source&gt;:20:19: warning: passing argument 1 of &#39;greatestOf&#39; makes pointer from integer without a cast [-Wint-conversion]
   20 |     greatestOf(arr[4], &amp;x); // here warning text. When I try to use &#39;&#39;&#39;greatest(arr, &amp;x)&#39;&#39;&#39;
      |                ~~~^~~
      |                   |
      |                   int
&lt;source&gt;:4:21: note: expected &#39;int *&#39; but argument is of type &#39;int&#39;
    4 | void greatestOf(int arr[], int *result) {
      |                 ~~~~^~~~~

I want the warning text to disappear, I think if want to send value to function I have to include the size of the array. Because I want to send the whole value

答案1

得分: 6

在函数调用中,arr[4] 是一个表示数组 arr 第五个元素的表达式,并不是在告诉函数 arr 有四个元素。相反,你只需传递 arr。然而,这会导致一个问题,即如何告诉 greatestOf 数组 arr 的长度。

在这种情况下,你知道传递给 greatestOf 的数组总是包含四个元素,所以你可以简单地将 greatestof 的签名更改为:

void greatestOf(int arr[4], int *result) 

在这里,int arr[4] 是一个类型,而不是一个表达式,表示长度为 4 的名为 arr 的数组。

如果你不知道 arr 有多长,那么你就需要将其长度作为一个单独的参数传递,像这样:

void greatestOf(int arr[], int arr_length, int *result) {
    *result = arr[0];

    for (int i = 1; i < arr_length; i++) {
        if (arr[i] > *result) {
            *result = arr[i];
        }
    }
}

然后像这样调用它:

greatestOf(arr, 4, &x);
英文:

In the function call, arr[4] is an expression that represents the fifth element of arr, not that you're telling the function that arr is four elements long. Instead, you just pass arr. However, that leaves the problem of telling greatestOf how long arr is.

In this case, you know that the array passed to greatestOf will always four elements long, so you can just change the signature of greatestof to

void greatestOf(int arr[4], int *result) 

Here, int arr[4] is a type, not an expression, meaning an array of length 4 with the name arr.

If you didn't know how long arr was, then you've have to pass its length as a separate parameter, like this:

void greatestOf(int arr[], int arr_length, int *result) {
    *result = arr[0];

    for (int i = 1; i &lt; arr_length; i++) {
        if (arr[i] &gt; *result) {
            *result = arr[i];
        }
    }
}

Then call it like this:

greatestOf(arr, 4, &amp;x);

答案2

得分: 5

在C语言中,函数参数通常是按值传递的。然而,直接按值传递数组给函数是不可能的<sup>*</sup>(见脚注)。通常,将数组传递给函数是通过传递指向数组第一个元素的指针来完成的。只有这个指针会按值传递。

然而,仍然允许将数组指定为函数参数,就像你所做的:

void greatestOf( int arr[], int *result )

但是当你这样做时,数组会退化为一个指针,所以声明等同于以下内容:

void greatestOf( int *arr, int *result )

因此,在声明函数参数方面没有问题。然而,在调用函数方面是有问题的。你是这样调用它的:

greatestOf(arr[4], &amp;x);

如前所述,通常通过传递指向数组第一个元素的指针将数组传递给函数。因此,正确的方式是这样调用它的:

greatestOf( &amp;arr[0], &amp;x );

然而,更常见的做法是简单地写成:

greatestOf( arr, &amp;x );

这是可能的,因为当你将数组传递给函数时,数组会自动退化为指向数组第一个元素的指针,即&amp;arr[0]

通过写arr[4],你传递的是数组(不存在的)第5<sup>th</sup>元素的值(数组索引是基于0的)给函数。这是错误的,因为你需要传递指向第一个元素的指针。

请注意,在声明数组时,必须在[]中指定数组的大小,但在表达式之外使用[]具有完全不同的含义:它表示你要对数组进行索引。

> 我认为如果要将值发送到函数中,我必须包括数组的大小。

如果数组的大小保证始终为4,就无需将数组的大小传递给函数。但在这种情况下,我建议你将函数声明

void greatestOf( int arr[], int *result )

改为

void greatestOf( int arr[4], int *result )

以便清楚地向阅读代码的任何人表明该函数接受一个指向长度为4的数组的指针。4将被编译器忽略,因为如前所述,数组声明会退化为一个指针,在这种情况下是int *arr

你也可以写成

void greatestOf( int arr[static 4], int *result )

这将告诉编译器参数arr保证是一个有效的指针(例如非NULL指针),指向一个至少有4个元素的数组。这样做可能会提高性能。

如果你希望函数greatestOf也能处理大小不等于4的数组,你可以像这样编写函数:

int greatestOf( int arr[], size_t length )
{
    int max;

    if ( length == 0 )
    {
        fprintf( stderr, "无效的数组大小!\n" );
        exit( EXIT_FAILURE );
    }

    max = arr[0];

    for ( size_t i = 1; i < length; i++ )
    {
        if ( arr[i] > max )
        {
            max = arr[i];
        }
    }

    return max;
}

请注意,此代码要求你在源文件的顶部添加#include <stdlib.h>

main函数中,现在可以这样调用函数main

x = greatestOf( arr, sizeof arr / sizeof *arr );

表达式sizeof arr / sizeof *arr是整个数组的大小(以字节为单位)除以单个数组元素的大小。因此,这个表达式将求得数组中的元素数量。

英文:

In C, function arguments are usually passed by value. However, it is not possible to directly<sup>*</sup> (see footnote) pass an array to a function by value. Passing an array to a function is usually done by passing a pointer to the first element of the array. Only this pointer is then passed by value.

However, it is still allowed to specify an array as a function parameter, as you are doing:

void greatestOf( int arr[], int *result )

But when you do this, the array will decay to a pointer, so the declaration is equivalent to the following:

void greatestOf( int *arr, int *result )

Therefore, there is nothing wrong with how you are declaring the function parameters. However, there is something wrong with how you are calling the function. You are calling it like this:

greatestOf(arr[4], &amp;x);

As previously stated, arrays are usually passed to functions by passing a pointer to the first element of the array. Therefore, the correct way would be to call it like this:

greatestOf( &amp;arr[0], &amp;x );

However, it is more common to simply write:

greatestOf( arr, &amp;x );

This is possible because when you pass an array to a function, the array will automatically decay to a pointer to the first element of the array, which is &amp;arr[0].

By writing arr[4] instead, you are passing the value of the (non-existant) 5<sup>th</sup> element of the array (array indexes are 0-based) to the function. This is wrong, because you need to pass a pointer to the first element.

Note that when declaring an array, you must specify the size of the array in [], but when used outside an expression, the [] has a completely different meaning: It means that you index into the array.

> I think if want to send value to function I have to include the size of the array

There is no need to pass the size of the array to the function, if the size of the array is guaranteed to always be 4. However, in that case, I suggest that you change the function declaration

void greatestOf( int arr[], int *result )

to

void greatestOf( int arr[4], int *result )

in order to make clear to anybody reading the code that the function takes a pointer to an array whose length is 4. The 4 will be ignored by the compiler, because, as previously stated, the array declaration will decay to a pointer, in this case int *arr.

You can also write

void greatestOf( int arr[static 4], int *result )

which will tell the compiler that the parameter arr is guaranteed to be a valid pointer (e.g. non-NULL) to an array which is guaranteed to be at least 4 elements long. Doing this may improve performance.

If you want the function greatestOf to also be able to handle arrays that have a size different than 4, you can write the function like this:

int greatestOf( int arr[], size_t length )
{
    int max;

    if ( length == 0 )
    {
        fprintf( stderr, &quot;Invalid array size!\n&quot; );
        exit( EXIT_FAILURE );
    }

    max = arr[0];

    for ( size_t i = 1; i &lt; length; i++ )
    {
        if ( arr[i] &gt; max )
        {
            max = arr[i];
        }
    }

    return max;
}

Note that this code requires you to add #include &lt;stdlib.h&gt; to the top of the source file.

In the function main, instead of calling the function main like this

greatestOf(arr, &amp;x);

you can now call it like this:

x = greatestOf( arr, sizeof arr / sizeof *arr );

The expresson sizeof arr / sizeof *arr is the size (in bytes) of the entire array divided by the size of a single array element. Therefore, this expression will evaluate to the number of elements in the array.


Footnote:

<sup>*</sup> It is possible to pass an array to a function by value, if it is enclosed in a struct. However, passing arrays by value is usually not recommended, because it creates a copy of the entire array, which can be bad for performance.

答案3

得分: 1

在不同上下文中使用的相似结构可以具有不同的含义。

在这个数组声明中:

int arr[4], x;

构造arr[4]表示一个具有四个元素的数组。

在这个函数调用中:

greatestOf(arr[4], &x);

构造arr[4]表示类型为int的不存在的标量元素,索引为4(数组的有效索引范围是[0, 3])。但是该函数期望的是int *类型的指针,而不是int类型的对象。

因此,编译器会发出警告。

请注意,编译器将数组类型的参数调整为指向数组元素类型的指针。这就是这个函数声明:

void greatestOf(int arr[], int *result);

被编译器调整为:

void greatestOf(int *arr, int *result);

要调用这个函数,您需要使用数组名,像这样:

greatestOf(arr, &x);

在这种情况下,数组标识符又会转换为指向其第一个元素的指针。也就是说,这个调用等同于:

greatestOf(&arr[0], &x);

至于您的函数,至少应该声明如下:

void greatestOf(const int arr[], size_t n, int *result);

首先,第一个参数应该使用const限定符声明,因为在函数内部不会改变数组的元素。

其次,您需要传递数组(或子数组)的元素数量给函数,而不是使用魔法数4

尽管即使像上面所示声明函数,函数仍然不安全。用户可以将值0作为第二个参数传递。在这种情况下,这个语句:

*result = arr[0];

会引发未定义的行为。

更好和更安全的方法是按以下方式声明和定义函数:

int *greatestOf(const int arr[], size_t n)
{
    const int *greatest = arr;

    for (size_t i = 1; i < n; i++)
    {
        if (*greatest < arr[i])
            greatest = arr + i;
    }

    return (int *)greatest;
}

然后可以像这样调用函数:

int *greatest = greatestOf(arr, 4);

printf("Greatest number: %d\n", *greatest);
英文:

Similar constructions used in different contexts can have different meanings.

In this declaration of an array

int arr[4], x;

the construction arr[4] denotes an array with four elements.

In this function call

greatestOf(arr[4], &amp;x);

the construction arr[4] denotes a non-existent scalar element of the type int with the index 4 (the valid range of indices of the array is [0, 3]) of the array arr. But the function expects a pointer of the type int * instead of an object of the type int.

So the compiler issues the warning.

Pay attention to that the compiler adjusts a parameter of an array type to pointer to the array element type. That is this function declaration

void greatestOf(int arr[], int *result);

is adjusted by the compiler to

void greatestOf(int *arr, int *result);

To call the function you need to use the array name like

greatestOf(arr, &amp;x);

In this case the array designator in turn is converted to pointer to its first element. That is this call is equivalent to

greatestOf( &amp;arr[0], &amp;x);

As for your function then it should be declared at least like

void greatestOf( const int arr[], size_t n, int *result);

firstly, the first parameter should be declared with the qualifier const because elements of the array are not changed within the function.

And secondly, you need to pass the number of elements of an array (or a sub-array) to the function instead of using the magic number 4.

Nevertheless even if to declare the function such a way as shown above the function is unsafe. The user can pass value 0 as the second argument. In this case this statement

*result = arr[0];

invokes undefined behavior.

It is much better and safer to declare and define the function the following way.

int * greatestOf( const int arr[], size_t )
{
    const int *greatest = a;

    for ( size_t i = 1; i &lt; n; i++ ) 
    {
        if ( *greatest &lt; a[i] ) greatest = a + i;
    }

    return ( int * )greatest;
}

And the function is called like

int *greatest = greatestOf( arr, 4 );

printf( &quot;Greatest number: %d\n&quot;, *greatest );

huangapple
  • 本文由 发表于 2023年5月28日 23:18:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76352180.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定