1

my question is about sizeof and Memory Allocation. When I was studying C and testing type values I tried this code:

#include <stdio.h>

int main(void) {
char vec[0];
vec[0] = 1;
printf("\n SIZEOF: %li", sizeof(vec));
printf("\n VEC[0]: %li", vec[0]);
}

The output was:

> SIZEOF: 0

> VEC[0]: 1

Why "vec[0]" has a size of "0 bytes" even I adding value "vec[0] = 1" ? (If I don't add this value, just declare the vector "char vec[0] or int vec[0]" the output is same).

Ricxk. ty for your time.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
ricxk
  • 67
  • 1
  • 10

4 Answers4

1

vec is defined as being an array which is zero elements in size. The size of zero elements is zero, which seems to be sensible. Assigning a value to vec[0] is overwriting memory somewhere.

1

Arrays must be defined with a positive size.

You created one with 0 size which is a constraint violation, so your code exhibits undefined behavior.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    gcc actually allows 0 length arrays as an extension (predating and meant to address the same thing as C99 flexible array members). Dereferencing one like this is still undefined, though. See https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Zero-Length.html – Shawn Apr 06 '21 at 16:16
  • @Shawn: You're still not supposed to use them outside of a struct. – Joshua Apr 06 '21 at 16:18
  • 1
    @Joshua But you *can*. The documentation warns against it, but it's allowed. – Shawn Apr 06 '21 at 16:26
  • @Shawn: The C tag says it is for questions about C as defined in the ISO 9899 standard unless otherwise specified. When GCC is in any mode where it accepts zero-length arrays without a diagnostic message, it is not implementing C as defined in the ISO 9899 standard, and its behavior is no more relevant to the issue than the behavior of a FORTRAN compiler is, because neither one is implementing C as defined in the standard. – Eric Postpischil Apr 06 '21 at 17:10
  • 1
    The real world behavior of actual compilers is very relevant to those of us who don't live in an ivory tower. I'm getting flashbacks to comp.lang.c in the 90's. – Shawn Apr 06 '21 at 17:54
  • I very nearly wrote a "what if the compiler is simply missing the check" answer that would have reported that no undefined behavior occurs until the array is indexed. – Joshua Apr 06 '21 at 21:34
  • @Shawn: GCC’s extension to allow zero-length arrays (which, if not accompanied by a diagnostic message, is actually a variation, not an extension) is not a “real world” issue here as it is of no use in defining a stand-alone zero-length array. It is a feature provided for its usefulness in structures before the standardization of flexible array members. For stand-alone arrays with a constant size of zero, it is not practically useful and bringing it up is not a matter of “real world behavior” but mere pedantry. – Eric Postpischil Apr 07 '21 at 11:56
1

This code snippet

char vec[0];
vec[0] = 1;

invokes undefined behavior.

You may not declare an array with zero elements.

From the C Standard (6.7.6.2 Array declarators)

1 In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type. The optional type qualifiers and the keyword static shall appear only in a declaration of a function parameter with an array type, and then only in the outermost array type derivation.

Pay attention to that there are used incorrect conversion specifiers in these calls of printf

printf("\n SIZEOF: %li", sizeof(vec));
printf("\n VEC[0]: %li", vec[0]);

For a value returned by the operator sizeof that has the type size_t you should use the conversion specifier %zu and for an object of the type char you should use the conversion specifier %c.

As for your question

Why "vec[0]" has a size of "0 bytes" even I adding value "vec[0] = 1" ? (If I don't add this value, just declare the vector "char vec[0] or int vec[0]" the output is same).

then the compiler should issue a message relative to the invalid declaration of an array.

As for the output then as the array is not a variable length array then the value of the expression sizeof( vec ) is evaluated at compile time. The compiler sees that the number of elements is equal to 0 and it calculates the expression sizeof( vec ) as 0 * sizeof( char ). Thus this expression always yields 0 independent on the array element type.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • You would only use `%c` if you want to print a char as a character. If you want to print a char as a (decimal) integer, use `%i` or `%d`. – Chris Dodd Apr 06 '21 at 16:34
  • 1
    In a great many compilers, declaring an array with 0 elements is legal. It is particularly useful when making structures with flexible sizes where the last field of the structure is a zero-length array. – abelenky Apr 06 '21 at 16:38
  • @abelenky Flexible arrays that are members of structures and such declarations as in the question are two different things. Moreover a flexible array member is declared as having an incomplete type. So your comment does not make a sense. – Vlad from Moscow Apr 06 '21 at 16:43
  • *"You may not declare an array with zero elements."* - Yes, you can, in certain circumstances. Your blanket statement is misleading at best, more likely wrong. – abelenky Apr 06 '21 at 16:59
  • @abelenky Write to the C Standard Committee that the quote from the C Standard I provided is incorrect. – Vlad from Moscow Apr 06 '21 at 17:01
  • @VladfromMoscow: The quote is correct but your assertion that you may not declare an array with zero elements is incorrect. The quote from the C standard binds the C implementation, and it dictates that the C implementation must issue a diagnostic message. The C standard does not bind the C programmer; they are allowed to write code that violates constraints. – Eric Postpischil Apr 06 '21 at 17:06
  • @EricPostpischil The word "shall" means that such declarations are not acceptable according to the C Standard. As for you as a programmer then of course you can write code that breaks the C Standard. No problems. – Vlad from Moscow Apr 06 '21 at 17:08
  • @VladfromMoscow: The C standard does not have jurisdiction over programmers and cannot give itself jurisdiction over programmers. Whatever words it uses, it has no claim to dictate what programmers may or may not do. – Eric Postpischil Apr 06 '21 at 17:12
  • @EricPostpischil As I have just written you of course can write any code that breaks the C Standard. :) – Vlad from Moscow Apr 06 '21 at 17:14
  • @VladfromMoscow: It means that the code is not *strictly* conforming. The Standard was intended to allow programmers to write portable code, but not require that they do so. The Standard does not require that compilers behave usefully when given programs that violate constraints, and such programs are non-portable, but the authors of the Standard have expressly stated that they did not wish to demean useful programs that happen not to be portable. – supercat Apr 06 '21 at 19:20
  • @supercat It means undefined behavior and nothing more. "If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtime constraint is violated, the behavior is undefined." – Vlad from Moscow Apr 06 '21 at 19:25
  • @supercat And " Undefined behavior is otherwise indicated in this International Standard by the words ‘‘undefined behavior’’ or by the omission of any explicit definition of behavior" – Vlad from Moscow Apr 06 '21 at 19:28
  • @VladfromMoscow: And Undefined Behavior means nothing more nor less than that the Standard imposes no requirements. Among other things, that allows implementations to, as a form of "conforming language extension", specify behavior in cases where the Standard does not. It implies nothing about whether failure to support an extension might make an implementation unsuitable for some purposes. – supercat Apr 06 '21 at 19:29
  • @supercat Reread the quote from the C Standard where in bold there is used the word "shall". – Vlad from Moscow Apr 06 '21 at 19:33
  • @VladfromMoscow: Reread the portion that specifies what the Standard means when it uses the term "shall", and read also the requirements for "conforming" and "strictly conforming" programs. Also read the published Rationale document. The way the C Standard uses the term "shall" is unique or nearly so, but the authors recognized that a lot of code relied upon constructs that were supported by 90%+ of compilers, but might not be supportable on 100%. The intended that such "popular extensions" be supported on a quality-of-implementation basis where practical, as determined by the marketplace. – supercat Apr 06 '21 at 19:51
  • @supercat I need not reread this because this case forms undefined behavior. – Vlad from Moscow Apr 06 '21 at 19:57
  • @VladfromMoscow: Behavior which is not defined by the Standard, but which the Standard allows, and was not intended to particularly discourage, implementations to treat as a "conforming language extension". – supercat Apr 06 '21 at 19:57
  • @supercat Where did you find that it is allowed?! The Standard says clear that it is not allowed. The size specified by an integer constant of the array SHALL be greater than zero. Otherwise there would be written that it is implementation defined whether such a declaration is valid or not. – Vlad from Moscow Apr 06 '21 at 20:00
  • The Standard only uses the phrase "implementation-defined" for things which all implementations are required to treat meaningfully. It also defines "strictly conforming C programs", which are required to abide all constraints and refrain from Undefined Behaivor, differently from "conforming C programs", upon which it places no such requirements. Per the Rationale, "The goal is to give the programmer a *fighting chance* to make powerful C programs that are also highly portable, without seeming to demean perfectly useful C programs that happen not to be portable, thus the adverb *strictly*." – supercat Apr 06 '21 at 20:11
  • @supercat breaking a shall requirement is undefined behavior. You can write a code with undefined behavior. But then do not refer to the C Standard that you may write such a code as you are doing now. – Vlad from Moscow Apr 06 '21 at 20:14
  • @VladfromMoscow: About what kind of behavior did the authors of the Standard say "It also identifies areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior." See http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf page 11. The Committee made no attempt to specify everything that would be necessary to make an implementation suitable for every imaginable task, or even *any* particular task, but expected the marketplace to determine what implementations should support what constructs. – supercat Apr 06 '21 at 20:21
  • @supercat We are speaking about constructions from the C Standard point of view. And the C Standard says that such a declaration is invalid and has undefined behavior. – Vlad from Moscow Apr 06 '21 at 20:23
  • 2
    @VladfromMoscow: The C Standard forbids some constructs in "Strictly Conforming C Programs'. On the other hand, it allows a "Conforming C Program" to use any extension which is accepted by at least one "Conforming C Implementation". The fact that there exist C implementations which will usefully process size-zero array declarations is, by the Standard's terminology, sufficient to allow such a construct in a "Conforming C Program". – supercat Apr 06 '21 at 20:24
0

You are not actually filling a position in the "array" of length 0 vec when you write vec[0] = 1;.

Remember, when you declare an array of length N, its valid indices are 0, 1, 2 ... N-1. What are the valid indices if an array has size 0? None of them!

This is the same sort of undefined behavior as:

int data[3] = { 1, 2, 3 };
data[10000] = 10;

It may work on your system to write to vec[0], but it's still not memory that belongs to the vec.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85