Weird behavior of sizeof for arrays passed as parameters [duplicate]

人盡茶涼 提交于 2019-12-08 07:12:32

问题


Can you explain this:

void foo(const char data[10])
{
   char copy[10];
   const char copy1[10] = {};

   printf("%i", sizeof(copy)); //prints 10, as expected
   printf("%i", sizeof(copy1)); //prints 10, as expected
   printf("%i", sizeof(data)); //prints 4, WTF?

}

Looks like function parameters are treated as simple pointers for sizeof. But WHY does this happen? Is it documented anywhere?


回答1:


I never saw that syntax before in C++ but maybe you meant

void foo(const char data[10])

Anyway, in C++ arrays decay to pointers when passed to a function. So the function has no way of knowing how big the passed arrays are. In that sense, what I wrote above is completely equivalent to:

void foo(const char data[])

There is also a C FAQ about this subject.




回答2:


When you pass an array to a function, what you are actually doing is passing a pointer to the first element of the array (you probably knew that). Even if you have a parameter declared as char[10], that will still mean you only get a pointer since C is designed to be very fast so it avoids making copies of potentially very large data such as arrays. The [10] serves no purpose, except maybe as a reminder to the programmer.




回答3:


There are actually two related but independent rules in play here.

One is that an expression of array type is, in most contexts, implicitly converted (at compile time) into a pointer to (i.e., the address of) the first element of the array. The exceptions are when it's the operand of sizeof, when it's the operand of unary &, and when it's a string literal in an initializer used to initialize an array object.

The other is that a function parameter declared to be of an array type is really of a pointer type -- and if the array type includes a length, that length is silently ignored. This is the rule that causes the behavior you're seeing.

Strongly recommended reading: Section 6 of the comp.lang.c FAQ.

EDIT : Your program has several errors that would prevent it from compiling, which means you couldn't have seen the results you say you're seeing. You apparently re-typed the program when posting it here. Instead, you should copy-and-paste the exact code as you fed it to the compiler.

Here's a corrected version of your code, with a bit of commentary added.

#include <stdio.h> /* required for printf */

void foo(const char data[10]) /* NOTE: The 10 is quietly ignored */
{
    char copy[10];
    /* syntax, [10] follows "copy", not "char" */
    const char copy1[10]; // = {};
    /* as above, and standard C disallows empty initializer */

    printf("%d", (int)sizeof copy);  // prints 10, as expected
    printf("%d", (int)sizeof copy1); // prints 10, as expected
    printf("%d", (int)sizeof data);  // prints 4 (sizeof (char*), as expected

    /*
     * "%i" or "%d" requires an int argument; sizeof yields size_t.
     * You need to convert the result.
     * "%d" is more common and idiomatic than the equivalent "%i"
     * When sizeof is applied to an expression, no parentheses are needed
     * (it's an operator, not a function
     */
}



回答4:


You are passing address of 1st element. When we call foo() method the compiler generates a pointer to its first element. Array name is itself a pointer to the first element.




回答5:


Other answers already mention that this is because a function parameter of declared as an array type actually declares a parameter of pointer type; this is specified in C++11, 8.3.5/5:

After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively.

Therefore, data actually has type const char *, so sizeof data gives the size of a pointer.

You can preserve the size of an array by passing a reference to it:

void foo(const char (&data)[10])
{
   char copy[10];
   const char copy1[10] = {};

   printf("%i", sizeof(copy)); //prints 10, as expected
   printf("%i", sizeof(copy1)); //prints 10, as expected
   printf("%i", sizeof(data)); //prints 10, as expected
}

The reference must be to an array of known size, since 8.3.5/8 says:

If the type of a parameter includes a type of the form “pointer to array of unknown bound of T” or “reference to array of unknown bound of T,” the program is ill-formed.

You can get around this using a function template, parametrised by the size of the array:

template <size_t N>
void foo(const char (&data)[N]);



回答6:


Try this code below. If your string is initialized with anywhere from 1-9 characters, you'll be able to get the length of it this way. The max is 9 characters because you must have room for the '\0' terminating character.

Incidentally, if your string is not initialized, the strlen in foo() does not report zero as I would expect, but rather some unexpected number. Perhaps someone more experienced than me can comment on this.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void foo(const char * data1, const char * data2)
{
   char copy[10];
   const char copy1[10] = {};

   printf("%i\n", sizeof(copy)); //prints 10, as expected
   printf("%i\n", sizeof(copy1)); //prints 10, as expected
   printf("%i\n", (sizeof(*data1) * strlen(data1))); //prints 1
   printf("%i\n", (sizeof(*data2) * strlen(data2))); //prints 9
}

int main(void)
{
    const char bar1[10] = "1";
    const char bar2[10] = "123456789";

    printf("%i\n", sizeof(bar1)); //prints 10, as expected
    printf("%i\n", sizeof(bar2)); //prints 10, as expected
    foo(bar1, bar2);
    return 0;
}


来源:https://stackoverflow.com/questions/8642741/weird-behavior-of-sizeof-for-arrays-passed-as-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!