what is the size of globally declared array in c? - c

#include <stdio.h>
char A[];
int main()
{
printf("%c\n",A[1]);
return 0;
}
I can access any element using index . It never gives error . What is the index of max element i can access for 32 bit machine?

It has size 1. Accesses beyond index 0 (including your code, which accesses A[1]) have undefined behavior.
This is 6.9.2 in the C99 standard. char A[]; is a "tentative definition", which roughly speaking means that if the same translation unit contains a proper definition then it's just a declaration of A as an array of char of unknown size. If there's no proper definition then the object is defined anyway as if there were a definition at the end of the translation unit, with a default initializer.

When the declaration char A[]; appears at file scope, it declares an array. A definition of the array should appear somewhere else. If the definition does not appear in the same file (translation unit), then the behavior is as if a definition appeared with one initializer with value zero, as if you had written char A[] = { 0 };.
Code in which the declaration is visible may use the array. However, if the definition of the array is not visible, then the compiler does not know the size of the array. It is the responsibility of the author of the code to use only elements that are actually defined. They must know the size of the array by prior arrangement or by passing some information in the program.
If code uses an element of the array that does not exist, or even calculates an address of an element more than one beyond the end of the array, then the behavior is undefined.

A[1] will be translated as *(A+1) which is basically a memory address . So, printf can print whatever is at that memory location. I assume you can keep referencing the array till anything exists at that location (which gives you garbage)[and you are permitted to access that location].
Edit: GCC 4.6.3 gives warning: array ‘A’ assumed to have one element [enabled by default]

I can access any element using index . It never gives error . What is
the index of max element i can access for 32 bit machine?
There are a great many things that you can do in C which you nevertheless should not do. Accessing out of bounds elements of an array is usually one of those things.
When I compile your code using gcc, I get:
warning: array ‘A’ assumed to have one element
That should be enough to tell you that you should not access any element other than A[0].

It's just a pointer, there are no elements in the table. You should not try to index anything.

Related

No compiler warning by inconsistent function parameter use

During a C code review of the software that did not want to run on the target HW, the following inconsistency has been discovered in a function use:
The SW component 1 implements the function:
void foo(uint8 par_var[2])
The function foo() also writes the two element of the par_var array.
The SW component 2 gets an external declaration of the foo() as following
extern void foo(uint8 *par_var)
and uses it as following :
uint8 par_var;
foo(&par_var); //-> sending a pointer to a scalar
// instead to an array of 2 elements.
Obviously, it may lead and leads actually to the program failure.
The question is, if it could be possible for compiler/linker to intercept the inconsistency by issuing a warning, for example.
I have scanned and tried some of the gcc (CygWin) compiler options along with the standard ones (-Wall, -pedantic ) https://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Warning-Options.html
but could not find one that could issue a corresponding warning .
There is a C feature that could aid a compiler in diagnosing this, but I am not aware of a compiler that takes advantage of it and warns. If foo were declared as void foo(uint8 par_var[static 2]);, then a caller is required to pass a pointer to at least two elements, per C 2018 6.7.6.3 7:
If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
So, a compiler seeing uint8 par_var; foo(&par_var); could recognize the failure to pass two elements and provide a warning. (While I am not aware of compilers that check the declared size, some compilers will warn when a null pointer is passed for such a parameter.)
As is well known, in the declaration void foo(uint8 par_var[2]), par_var is automatically adjusted to uint8 *par_var. As an alternative, instead of passing a pointer to uint8, you could pass a pointer to an array of uint8 by declaring foo as void foo(uint8 (*par_var)[2]);.
Then you would have to pass it an array, such as:
uint8 A[2];
foo(&A);
If it were called with a pointer to uint8, the compiler should issue a warning. Unfortunately, this also constraints the routine; you must pass it a pointer to an array of two uint8 and cannot pass it a pointer to a larger array or a pointer to a uint8 in a larger array. So it has limited use. Nonetheless, it could serve in certain situations.

What do I get if I declare an array without a size in global scope?

In one of the answers in Tips for golfing in C, I saw this code (ungolfed version):
s[],t;
main(c){
for(scanf("%*d "); ~(c=getchar()); s[t++]=c)
putchar(s[t]);
}
I think that the above program exhibits UB (but who cares in code golf?). But the thing that I don't understand is the s[] in global scope. I know that when the type of a global variable isn't specified, it defaults to int. I created a small program which surprisingly compiles:
#include <stdio.h>
int s[];
int main(void)
{
printf("Hello!");
}
though it emits one warning:
prog.c:23:5: warning: array 's' assumed to have one element [enabled by default]
int s[];
^
What is s in the above program? Is it an int* or something else?
Will this be useful anywhere?
What is s in the above program? Is it an int* or something else?
s is an incomplete type. That's why you cannot sizeof it. As #BLUEPIXY suggests, it's initialized with zero because it's declared in global scope making a "tentative definition".
int i[];
the array i still has incomplete type, the implicit initializer causes it to have one element, which is set to
zero on program startup.
Now,
Will this be useful anywhere?
It's pretty useless if you're just using s[0] because at that point you go for s; directly. But, if you need an array with a certain size and you don't care about UBs, it's "okay".

Is there anything wrong with `something_t* x = malloc(sizeof(*x))`?

I'm writing some extremely repetitive code in C (reading XML), and I found that writing my code like makes it easier to copy and paste code in a constructor*:
something_t* something_new(void)
{
something_t* obj = malloc(sizeof(*obj));
/* initialize */
return obj;
}
What I'm wondering is, it is safe to use sizeof(*obj) like this, when I just defined obj? GCC isn't showing any warnings and the code works fine, but GCC tends to have "helpful" extensions so I don't trust it.
* And yes, I realize that I should have just written a Python program to write my C program, but it's almost done already.
something_t* obj = malloc(sizeof(*obj));
What I'm wondering is, it is safe to use sizeof(*obj)
like this, when I just defined obj?
You have a declaration consisting of:
type-specifier something_t
declarator * obj
=
initializer malloc(sizeof(*obj))
;
The C standard says in section Scopes of identifiers:
Structure, union, and enumeration tags have scope that begins just
after the appearance of the tag in a type specifier that declares the
tag. Each enumeration constant has scope that begins just after the
appearance of its defining enumerator in an enumerator list. Any other
identifier has scope that begins just after the completion of its
declarator.
Since obj has scope that begins just after the completion of its declarator, it is guaranteed by the standard that the identifier used in the initializer refers to the just defined object.
While we are giving the sizeof like this.
something_t* obj = malloc(sizeof(obj));
It will allocate the memory to that pointer variable as four bytes( bytes allocated to a pointer variable.)
something_t* obj = malloc(sizeof(*obj));
It will take the data type which is declared to that pointer.
For example,
char *p;
printf("%d\n",sizeof(p));
It will return the value as four.
printf("%d\n",sizeof(*p));
Now it will return value as one. Which is a byte allocated to the character. So when we are using the *p in sizeof it will take the datatype. I don't know this is the answer you are expecting.
It's safe. For example,
n = sizeof(*(int *)NULL);
In this case, NULL pointer access doesn't occur, because a compiler can caluculate the size of the operand without knowing the value of "*(int *)NULL" in run time.
The C89/90 standard guarantees the 'sizeof' expression is a constant one; it is translated into a constant (e.g. 0x04) and embedded into a binary code in compilation stage.
In C99 standard, the 'sizeof' expression is not always a compile-time constant, because of introducing variable length array. For example,
n = sizeof(int [*(int *)NULL]);
In this case, the value of "*(int *)NULL" needs to be known in run time to caluculate the size of 'int[]'.

what is foo in int **foo[][]()

I am currently studying for my C-Midterm and I encountered this declaration:
int **foo[][]()
When looking for the solution as to what this declaration means my tutors actually gave two different answers:
1) foo is an array of arrays of functions with return type pointer to pointer to an int
2) foo is an array of arrays of pointers to pointers to a function with return type int
I know the "start with the name of the variable, continue to the right until you reach the end or ')' then go back to your last starting point and continue to the left until you reach the start or '('" rule so I think 1) is the correct answer here but I am not entirely sure.
Thanks,
Ozelotl
It is nothing specific. Meaning that on the surface it looks like a C declaration, but it is not well-formed. It is illegal and as such it means nothing.
Firstly, it appears like a two-dimensional array declaration, but in C language an array declaration is required to specify all sizes except possibly for the very first one. Your declaration omits the second size as well, which makes it illegal.
Secondly, even if we ignore the missing sizes, it looks like a declaration for an array of functions. It is illegal to declare arrays of functions in C.
For example, this would make a legal C declaration
int (**foo[][42])()
but not what you have originally.
The syntax of this declaration is that foo[][] declares a 2-D array (or it would, if the second bound had a dimension specified - as it stands that's illegal); and then the rest of it is:
int **bar(); // with bar = foo[][]
which is a function taking unspecified arguments and returning int **. However, since bar is an array type here this attempts to declare an array of functions, which is illegal. (Not to be confused with an array of function pointers, which would be OK).
The grammar rules are that the ** bind to the int (not to the bar) unless you use parentheses to force them to bind to the bar; so they are part of the type int ** and they are not saying that bar is a pointer.

For a structure variable,why is the initializer {21,19,3.6} same as {{21,19},3.6},but not vice-versa?

In the following example,I've illustrated this using two structures test1 and test2.The first has two elements-an integer array sized two,and a float element.The second structure has 3 elements,2 integers and one float.
I initialize two structure variables s1 and s2 for test1 as:
s1={{23,52},2.5},s2={21,19,3.6};
Both work fine even though for s2 I have taken out the braces that enclose the array elements.It works fine without warning and output is correct.But when I initialize 2 variables for test2 as follows:
v1={{23,52},2.5},v2={21,19,3.6};
I get incorrect output when I try to print out values of v1 and these are the warnings that I had got upon compilation:
warning: braces around scalar initializer|
warning: (near initialization for 'v1.list1')|
warning: excess elements in scalar initializer|
warning: (near initialization for 'v1.list1')|
||=== Build finished: 0 errors, 4 warnings ===|
Based on this premise,please clear the following doubt that arise:
Question: If using v1={{23,52},2.5} instead of v1={23,52,2.5} confuses the compiler about whether the first 2 numbers are distinct integer elements of the structure or part of an integer array element of the structure,then why doesn't using s2={21,19,3.6} instead of s2={{21,19},3.6} confuse the compiler into thinking that the structure varialbe s2 has 3 elements (2 integer elements and one float),instead of 2 elements (one integer array of size 2 and a float)?What I especially want to understand is why is the first case about v1's initialization wrong.
#include<stdio.h>
struct test1{
int list[2];
float rate;
}s1={{23,52},2.5},s2={21,19,3.6}; //Works fine
struct test2{
int list1;
int list2;
float rate;
}v1={{23,52},2.5},v2={21,19,3.6}; //Messes things up
int main(void)
{
printf("%d,%d,%f\n",s1.list[1],s2.list[1],s2.rate);
printf("%d,%d,%f\n",v1.list1,v1.list2,v1.rate);
}
This is just a consequence of how the rules for initialisers are defined. If the current object of the initialisation is a struct, union or array, then if the next initialiser begins with a { then the initialisers enclosed by that brace and its matching } are used to initialise the members of that object; otherwise, it just marches through the list of initialisers, taking as many as it needs.
So, in the first case s1={{23,52},2.5}, the current object starts out as s1.list. This is an array, and the next initialiser is { 23, 52 }, so that's used to initialise the array. s1.rate is now the current object, and the next initialiser is 2.5, so that works as expected.
In the second case s2={21,19,3.6}, the current object starts out as s2.list. This is an array, but the next initialiser does not start out with { - so it takes as many values as it needs (in this case, two), and initialises the array with 21 and 19. s2.rate is now the current object, and the next initialiser is 2.5, so again that works as expected.
In the third case v1={{23,52},2.5}, the current object starts out as v1.list1. This is a scalar, and the corresponding initialiser is {23, 52}. This violates a constraint of the language - "The initializer for a scalar shall be a single expression, optionally enclosed in braces" - so that's why you get a warning. Formally the behaviour of your program is undefined, but it appears that your compiler just uses the first value contained in the initialiser and discards the excess ones. The current object is now v1.list2, and the next initialiser is 2.5, so the wrong value is used to initialise this member. There is no initialiser for v1.rate; since v1 has static storage duration, this member is initialiser to 0.0.
In the forth case v2={21,19,3.6}, the current object starts out as v1.list1, and the next initialiser is 21 - this value is used to initialise the member. After this the current object is v1.list2 and the next initialiser is 19; then v1.rate is the current object and the next initialiser is 3.6.
For minimum confusion, you should always use a brace-enclosed initialiser for each struct or array subobject.
In the case of the variable s2, the compiler knows the size of the embedded array, so it can properly assign to it even without the bracers. you might however get a warning that suggests you to use bracers, and if you don't then I suggest you enable more compiler warnings (it's good to fix warnings, as they might indicate errors that might be valid C but invalid logic).
In the case v1, you can't use extra bracers because there is no compound data type (structure/union/array). The bracers {} can only be used to initialize compound data types.

Resources