sizeof() function in C [duplicate] - c

This question already has answers here:
What does sizeof(&array) return?
(4 answers)
Closed 9 years ago.
main()
{
char a[] = "Visual C++";
char *b = "Visual C++";
printf("\n %d %d",sizeof(a),sizeof(b));
printf("\n %d %d",sizeof(*a),sizeof(*b));
}
sizeof(a) gives me output: 11 ( that is length of the string)
Why is it so ?
Why isn't the output sizeof(a)=4 since when I try to print a it gives me an address value and hence an integer?

Whenever you refer to the name of the array in your program, It normally decays to a pointer to the first element of the array. One of the exception to this rule is the sizeof operator. So when you consider the following code.
int main()
{
char a[] = "Visual C++";
printf("sizeof(a)=%d\n",sizeof(a)); /* Here sizeof(a) indicates sizeof array */
printf("a=%p",a); /* Here the array name, passed as an argument to printf decays into a pointer of type (char *) */
return 0;
}

In the declaration char a[] = "Visual C++", a is an array of 11 char. So its size is 11 bytes.
In the declaration char *b = "Visual C++", b is a pointer to char. So its size is four bytes (in the C implementation you are using).
In the expression printf("%s", a), a is also an array. However, it is automatically converted to a pointer to the first element of the array. So a pointer to char is passed to printf.
This conversion happens automatically unless an array is the argument of &, sizeof, or _Alignof or is a string literal used to initialize an array of char. Because it happens automatically, people tend to think of array names as pointers. However, they are not.
Incidentally, sizeof is an operator, not a function.

When sizeof is applied to the name of a static array (not an array allocated through malloc), the result is the size in bytes of the whole array. This is one of the few exceptions to the rule that the name of an array is converted to a pointer to the first element of the array, and is possible just because the actual array size is fixed and known at compile time, when sizeof operator is evaluated.

There are lots of errors, here.
"sizeof(a) gives me output: 11 (length of the string)"
The length of the string is 10, not 11. sizeof(a) gives you the length of the array.
"why is it so, why isn't the output sizeof(a)=4 since when I try to print a it gives me an address value"
Here are two methods of "printing a" which do not "give you an address value":
puts(a);
and:
printf("%s\n", a);
so your logic is flawed, and this is the source of your confusion. "Printing a" only "gives you an address value" when you explicitly or implicitly elect to do so.
sizeof(a) gives 11 in this case because the C language defines the sizeof operator to give you the size of an array when an array is the operand. This, I'd argue, is the most natural behavior people would expect, so presumably that's why it is defined as such.
"and hence an integer."
In any case, an address is an address, not an integer. At best you could argue that it ought to give you the size of a pointer, but certainly not the size of an integer.

Related

C int array and pointer interaction [duplicate]

This question already has answers here:
How does sizeof know the size of the operand array?
(12 answers)
Arrays decaying into pointers
(2 answers)
What is array to pointer decay?
(11 answers)
Closed 5 years ago.
The following code...
int array[] = {17, 18, 19};
printf("Location of array: %p\n", array);
printf(" Value of array: %d\n", *array);
printf(" Size of array: %d bytes\n", sizeof(array));
Produces the output
Location of array: 0x7ffd0491c574
Value of array: 17
Size of array: 12 bytes
When I use variable array on the second line, it refers to the location of the "17". When I use it on the third like, it dereferences the pointer and prints out the number 17. Those, I understand.
On the last line, it prints out "12 bytes" as the size of the array. Why doesn't it print out 4 bytes, since in the previous two uses of the same variable, it seems to exclusively refer to the zero index of the array? How does sizeof know to look at the remainder of the array, instead of just printing out 4 bytes (as it would if I ran (sizeof(*array))?
When passed to sizeof, an array name doesn't decay into pointer, so the whole array size is found.
In the first case, it decays into pointer to the first element and the address is printed.
In the second case, we dereference the address, which is basically the value at the address pointed by the array name, namely the first element.
Why doesn't it print out 4 bytes?
From the C standard $6.5.3.4 (sizeof operator)
When applied to an operand that has array type, the result is the
total number of bytes in the array.
This answers your question why when passed an array name it shows the number of bytes. Here the array has 3 elements and each of size sizeof int or 4 Bytes in your system and so the total size = 3*4 = 12
What is *array?
*array is nothing other than array[0]. array decays into pointer to the first element of the array and then we dereference it. What is the value that is there? That is the value 17.
Why sizeof(*array)=4?
Well if you remember array is an array of 3 integers. So ofcourse the value contained in it is of type int. In your system sizeof int is 4 bytes. That's why you will get 4 as a result sizeof *array .
How sizeof works?
sizeof is implemented by the compiler. For non-VLA type of objects sizeof is a constant which is resolved compile time. But in case of VLA the array size is known at run time and that generates the result. So this is an expression for VLA.
Here,
sizeof(number of array elements * sizeof data_type)
sizeof(3 * 4)
sizeof int generally 4 bytes.
sizeof gives 12 bytes.
Here array is the pointer to an array of 3 integers, so if you are the printing size of the array, it will give you 12 bytes as each integer takes 4 bytes.
As you know array will have starting location of the array, now you are printing integer at the address "array" by using format specifier %d. It will print integer stored in first 4 bytes of the array,i.e. 17.
sizeof(*array) would give you sizeof(int) (seemingly 4 on your computer).
sizeof(array) gives 12 because sizeof(*array) gives 4, and you have 3 of these (int), 3 x 4.
array is an area in memory where the 3 integer are stored
<int0><int1><int2>
^
array
sizeof(array) gives the size of that space occupied by that area.
Mentioning array as itself in, for instance, int *p = array; stores the address of array in the pointer p.
Arrays in C are not exactly pointers, which is used to be in early days. Array names are decay into pointer based on the use of identifier(variable). Array names were pointer which caused problem with structure containing the array member, storing the pointer in array eventually lead to problem with structure members. So it was decided by the author of C to make array as name to location rather than the pointer some location. When used with * it will decay into pointer. Which allow us to use the array as a[i], i[a], *(a+i) .
sizeof() is a operand evaluated at compile time. The compiler knows the size, because it creates the array.

s[ ] is an array.&s should give address of decayed pointer [duplicate]

This question already has answers here:
How come an array's address is equal to its value in C?
(6 answers)
Closed 6 years ago.
After initialising character array name and address refers to same. s[] is an array. so it decays to pointer s, &s should give the address of pointer s
#include <stdio.h>
int main()
{
char s[]="Get Organised! learn C!";
printf("%u %s\n",&s[2],&s[2] );
printf("%u %s\n",s,s ); /* This line and below line is equivalent*/
printf("%u %s\n",&s,&s ); /* Please Explain */
printf("%u %s\n",s[2],s[2] );
printf("%u %s\n",s[3],s[3] );
return 0;
}
%u is just used to see what is going inside.
Getting rid of undefined behaviour first:
int main() {
char const string [] = "hello";
printf("%p %p\n", (void *) string, (void *) &string);
return 0;
}
You get (probably, that's target dependent) the same address printed here because the first expression is implicitly converted to a pointer to the first element of the array while the second is a pointer to the whole array (which most likely happens to start at its first element)
string == &(string[0]) // this is often called decaying
The type of the expression string (or more precisely the expression it decays to) is char const * whereas the type of &string is char const (*array)[6], so they're not "the same".
The reason that &string is not a pointer to a pointer is simple: The C standard explicitly forbids array expressions prefixed with the address of operator (&) (or inside an sizeof operator) to be implicitly converted to a pointer.
With the below, s is an array 100 of char. When is is passed to printf(), array s is converted to the value and type of the address of first element. So printf() is given a char *.
&s is the address of an array 100 of char. It has an equivalent value as s, yet a different type.
char s[100]="Whatever";
printf(some_format,s);
printf(some_format,&s);
To properly print addresses of variables, literals, cast to (void*) and use "%p". The print out typically lacks any description of the type of the variable.
printf("%p\n",(void*) s);
printf("%p\n",(void*) &s);
Output
0x28cbdc
0x28cbdc
To see an effect of the type difference:
printf("%zu\n",sizeof *(s));
printf("%zu\n",sizeof *(&s));
Output
1
100
#john bode also suggested this earlier.

Why I get the length of an array like this? [duplicate]

This question already has answers here:
Is an array name a pointer?
(8 answers)
Closed 6 years ago.
If I have:
int a[] = {1,2,3};
int len = sizeof(a) / sizeof(int);
I get 3, and I don't understand why.
They always taught me that an array is a pointer, doesn't store its length, but only the pointer to the first element.
Can someone explain this to me in a better way?
An array decays to a pointer to the first element of the array in most expressions. There are two cases where it does not and hence the outcome is not the same.
int array[5];
int* ptr = array; // Array decays to a pointer, OK.
// Same
int a = array[0];
int a = ptr[0];
// Same
void foo(int*);
foo(array);
foo(ptr);
// Not same
size_t s = sizeof(array); // s is 5*sizeof(int)
size_t s = sizeof(ptr); // s is sizeof(int*)
// Not same
int (*p1)[5] = &array; // p1 is a pointer to "an array of 5 ints"
int **p1 = &ptr; // p1 is a pointer to "an int*"
sizeof a returns the size of the entire array in storage units (bytes). sizeof (int) returns the size of a single integer in storage units. Since a is an array of 3 integers, sizeof a / sizeof (int) gives you 3.
They always taught me that an array that it is a pointer
"They" taught you incorrectly. Unless it is the operand of the sizeof or unary & operators, an array expression will be converted ("decay") to a pointer expression, and the value of the pointer expression will be the address of the first element of the array, but an array object is not a pointer.
When you declare a, what you get in memory looks something like this:
+---+
a:| | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
There is no object a that's separate from the array elements; there's no pointer anywhere.
They always taught me that an array that it is a pointer
That's your problem, right there. When you call a function and pass an array as an argument, it gets converted into a pointer to the first element. Otherwise, they're not equivalent. In particular, an array has an address, a type, and a size, whereas a pointer just has an address and a type.
This is a pretty common confusion among people learning C for the first time, and even some textbooks get it wrong.
edit: there are a few other cases where arrays "decay" to pointers, typically when they're used in an expression. See one of the other fine answers for a more-exhaustive treatment.
An array can decay to a pointer, but that does not mean an array is a pointer. See this SO question for details.
sizeof returns the size (in bytes) of the data type of its operand. In this case, the data type is an array of int of length three. But, since an int can be represented in different ways on different platforms, you must divide by the sizeof(int) to get the length.
See here for more details on sizeof.

what does sizeof() check as sentinel value for int array[] in c

Let us consider
int array[] = {2,33,4,56,7,8}; //case A
if sizeof() checked '\0' as end of char[] array!
what does sizeof(array) check as a sentinel value to find end of int array, therefore size of array in case A?
If I were to implement sizeof (intArray) , there is no liberty to access of sentinel value information ?
sizeof does not check anything. It only looks like a function call, but it is really an operator, a compiler trick to insert the size as known to the compiler at compile time.
Here is how sizeof interacts with C arrays: when you declare an array, you specify its size as a constant, as a run-time integer expression, or implicitly by supplying a certain number of values to put into your array.
When the number of elements is known at compile time, the compiler replaces sizeof(array) with the actual number. When the number of elements does not become known until runtime, the compiler prepares a special implementation-specific storage location, and stores the size there. The running program will need this information for stack clean-up. The compiler also makes this hidden information known to the runtime portion of sizeof implementation to return a correct value.
I think you're confusing string literals having a '\0' (null-terminator) in the end with arrays in general. Arrays have compile-time length known to the compiler 1. sizeof is an operator which gives the size based on the array length and the base type of the array.
So when someone does int a[] = {1, 2, 3}; there's no null-terminating character added in the end and number of elements is deduced as 3 by the compiler. On a platform where sizeof(int) = 4, you'll get sizeof(a) as 12.
The confusion is because for char b[] = "abc";, the element count would be 4 since all string literals have a '\0' automatically put up I.e. They are null-terminated automatically. It is not the sizeof operator which does a check for this; it simply gives 4 * sizeof(char) since for sizeof all that matters is the compile-time array length which is 4 = 1 + the number of characters explicitly stated in the string literal due to the nature of string literals in C.
However a character array not initialised by a string literal but with character literals doesn't have this quirk. Thus if char c[] = {'a', 'b', 'c'};, sizeof(c) would return 3 and NOT 4 as it is not a string literal and there's no null-terminating character. Again sizeof operator (not function) does this deduction at compile-time 2.
Finally, how the sizeof operator itself is implemented to do this, is an implementation detail not mandated by the standard. A standard talks about conditions and results. How they're achieved by implementations isn't a concern of the standard (or to anyone except the developers who implement it).
1 C99 introduced Variable Length Arrays (VLA) which allows arrays to have dynamic size.
2 Only for VLAs the sizeof operator and its operand are evaluated at run-time
sizeof is not a function, but a compile-time operator, that is replaced with the size of the variable. In case of true arrays (not pointers) it is replaced with the size in bytes of the content of the array, because it's knows at compile time;
Try the following to convince yourself:
void print_size(int[] array)
{
printf("%u\n", sizeof(array)); //Prints 4 (= sizeof(int*))
//May print 8 on 64b architectures
}
int main()
{
int array[] = {2,33,4,56,7,8};
printf("%u\n", sizeof(array)); //Prints 24 (= 6*sizeof(int))
print_size(array);
return 0;
}
This is because, inside of main, the compiler knows that array is an array of 6 ints, while the function print_size may be called with any array, and so its size is not known in advance: it is treated just like a int* (except that I'm not sure if it's a lvalue)

Arrays of strings in C

I need to hold an array of C strings. Now I know C strings are just an array of chars so essentially what I want is a 2d array of chars. The strings I'm trying to store will also never exceed 6 characters. My plan is to initialize a char array with 50 "string slots" and then if I hit 50 strings reallocate the array's memory to double it's capacity. I've tried something simple like:
int main() {
char strings[50][6];
strings[0] = "test";
printf("The string is: %s", strings[0]);
return(0);
}
But, when I go to compile it I get the following error:
test.c: In function ‘main’: test.c:3:
error: incompatible types when
assigning to type ‘char[6]’ from type
‘char *’ test.c:4: warning:
incompatible implicit declaration of
built-in function ‘printf’
Can anyone point in me in the right direction?
strncpy(strings[0], "test", 6); unless your C library has strlcpy(). However if you are going to need to vary the size of the storage, you're better off using a char ** with malloc(), realloc() and free().
One can't assign arrays directly in that way. In your current case, you would need to do something like...
strcpy (strings[0], "test");
It would be more idiomatic to use an array of pointers, though. Have a look at p111 and onwards of K & R.
Use strncpy (if at all possible) or strcpy for your assignment.
First the easy part. You do need to
#include <stdio.h>
to get rid of the incompatible printf warning. This has to do with the way the standard says C works, which is to allow you to make some function that is unlike the standard printf, the implicit declaration of that function with its signature (incorrectly) guessed by the compiler, and the compiler knowing that while you can define a different printf you probably didn't actually mean to.
Ok, now the more complicated part. Arrays in C are a little special. The can evaluate to pointer literals (which can't be assigned to, which is similar to trying to 6 = 4;), or they can evaluate to an entire array, depending on context. Usually they are pointer literals, but in this case strings[0] is seen as an array, which is why you get the error you got rather than one stating that strings[0] was an invalid l-value (left-value, meaning something that can be on the left side of a =). Either way you can't copy a character pointer literal (which is what "test" evaluates to) to an array. When you do this on the line where you declare a string (char array) the compiler treats it differently, though, which can cause some confusion. Anyway, you need to either use strcpy to copy the characters that make up "test" or initialize strings[0] to "test" like this:
char strings[50][6] = { "test" }; // only initializes the first member of the array
You can't assign array contents using the = operator. First of all, an array object cannot be a target of the assignment operator (Online C Standard, draft n1256, section 6.5.16.1, paragraph 1). strings[0] is an array object of type char [6], so it can't appear on the LHS of the = operator.
Second of all, when an array expression is not an operand of either the sizeof or address-of & operators and is not a string literal being used to initialize the contents of another array, the type of the expression is implicitly converted ("decays") from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array (section 6.3.2.1, paragraph 3).
The string literal "test" is a 5-element array of char (const char in C++) with static extent (meaning the memory for it is allocated at program startup and held until the program exits). However, when it appears in the expression
strings[0] = "test";
its type is converted from "5-element array of char" to "pointer to char" and its value is the address of the first element, so what you wind up doing is attempting to assign a pointer value to an array object, which is not a compatible type; bad juju, over and above not being able to assign an array object anyway.
If you want to copy the contents of one array to another, then you will need to either assign each array element individually, such as
strings[0][0] = 't';
strings[0][1] = 'e';
strings[0][2] = 's';
strings[0][3] = 't';
strings[0][4] = 0;
or even
size_t len = strlen("test");
size_t i;
for (i = 0; i < sizeof strings[0] - 1 && i < len; i++)
strings[0][i] = "test"[i]; // yes, you can subscript a string literal
strings[0][i] = 0;
or use a library function like memcpy(), strcpy(), strncpy(), strcat(), sprintf(), etc.:
strcpy(strings[0], "test");
or
strncpy(strings[0], "test", sizeof strings[0] - 1); // -1 to leave room
// for 0 terminator
// if necessary
or
sprintf(strings[0], "%*s", (int) sizeof strings[0] - 1, "test");
Note that you can initialize the array's contents when you declare it, like so:
char foo[] = "test"; // foo is implicitly sized to 5 (+1 for 0 terminator)
int bar[] = {1,2,3,4,5}; // again, size is implied from initializer
float f[3] = {1.0, 2.0, 3.0}; // Initializer cannot contain more items than
// array is sized for
I see there's a merry war over the use of strcpy() vs. strncpy() in the comments to another answer; my position is to use whichever one is appropriate to the given situation. If you know that your buffers are big enough to handle the largest possible input, use strcpy(). If not, use strncpy(), but be aware that you may have to add the 0 terminator manually.
The problem you have is in the way that the compiler interprets the statement char strings[50][6];
Instead of what you hoped, a char array with 50 slots for 6 char strings, you got a char array of single chars with dimesions 50x6.
Rather than char strings[50][6];, the way you want to initialise your array is as follows (I only know how to do this on the heap, sorry):
char ** strings[50] = malloc(50 * sizeof(char *));
for(int i = 0; i < 50; ++i)
{
strings[i] = malloc(50 * 6 * sizeof(char *));
}
Don't forget to clean with frees afterwards.
EDIT: And as said above. Before your main method. Inlcude the line #include <stdio.h>. This is where the printf() function is located.

Resources