#include <stdio.h>
#include <stdlib.h>
const int N = 5;
int main()
{
int vett[N] = {1, 2, 3, 4, 5};
return 0;
}
What is the problem in this part of code? the compiler report me these error and warnings:
error: variable-sized object may not be initialized
warning: excess elements in array initializer [enabled by default]
warning: (near initialization for 'vett') [enabled by default]
I know I can use the define directive to solve but I used to program in c++ and I don't want to change my old habits using const. There is something I can do? Thanks.
Unlike C++, even with const int N = 5, N is not considered as a constant expression in C. So int vett[N] is not a normal (fixed length) array, it's a variable length array.
In this case, you should still use:
#define N 5
You are using variable length arrays. Variable length arrays do not have an initializer. You need to initialize it using a loop. Note that, in C
const int N = 5;
doesn't mean N is constant (unlike in C++). Therefore int vett[N] declares vett as a variable length array.
You can write int vett[] = {1, 2, 3, 4, 5}; and the compiler will automatically determine how big your array is because you already determined the values to it.
Related
This is what I write:
const int MAX=100;
int main (){
int notas [MAX]={0};
The compiler says the following:
[Error] variable-sized object may not be initialized
[Warning] excess elements in array initializer
When I write MAX with #define MAX 100, it works. But I don´t understand what's the matter with doing it this way?
In this case
const int MAX=100;
does not create a compile time constant, so the array is treated as VLA. By definition, VLAs can not be initialised, hence the error.
On the other hand, #define MAX 100 is a pre-processor macro, and based on the textual replacement property, it results in a compile time constant value of 100, then the array is not a VLA and can be initialized as per the initialization rules.
This
const int MAX=100;
int main (){
int notas [MAX]={0};
is a declaration of a variable length array the size of which is determined at run-time because the declaration of the variable MAX is not a compile-time constant in C. Such arrays may not be initialized in declarations.
From the C Standard (6.7.9 Initialization)
3 The type of the entity to be initialized shall be an array of
unknown size or a complete object type that is not a variable length
array type.
So you could write for example
const int MAX=100;
int main (){
int notas [MAX];
memset( notas, 0, MAX * sizeof( int ) );
Otherwise you could use a compile time constant like
enum { MAX=100 };
int main (){
int notas [MAX]={0};
Despite the const in the declaration
const int MAX = 100;
MAX is not a constant expression (i.e., something whose value is known at compile time). Its value isn't known until run time, so the declaration of notas is treated as a variable-length array declaration, and a VLA declaration may not have an initializer (nor may a VLA be declared at file scope, nor may it be a member of a struct or union type).
With the preprocessor macro
#define MAX 100
all instances of the symbol MAX are replaced with the literal 100 after preprocessing, so it's effectively the same as writing
int notas[100] = {0};
which is why using the preprocessor macro works.
code snippet:
int *c[2] = {{1,2,3}, {4,5,6}};
gives warning:
warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int'
[-Wint-conversion]
int *c[2] = {{1,2,3}, {4,5,6}};
^
warning: excess elements in scalar initializer
int *c[2] = {{1,2,3}, {4,5,6}};
^
I suppose array {1,2,3} would decay to pointer so the assignment be legit?
Further more, according to the warning, why does the compiler think i'm trying to assign int to int *? instead of int array type to int *? Thanks in advance!
Bracketed initializers are not arrays, and so cannot undergo decay to a pointer type. And because c is an array of int *, each initializer needs to be of that type. Nested initializers only work with actual arrays (not pointers) or structs.
What you can do however is use compound literals in the initializer which do have an array type.
int *c[2] = {(int []){1,2,3}, (int []){4,5,6}};
I suppose array {1,2,3} would decay to pointer so the assignment be legit?
No. {1, 2, 3} is not an array, and no decay applies to it. It is an initializer suitable for initializing an array of three or more elements of arithmetic type, but you are trying to use it to initialize a pointer. You could do something like this, instead:
static int x[] = { 1, 2, 3 };
static int y[] = { 4, 5, 6 };
int *c[] = { x, y };
Or you could use compound literals to avoid declaring variables x and y, as another answer suggests. In either of these cases, the initializer elements are arrays, and they do decay to pointers.
This is the following code:
Why it is giving segmentation fault when I try to access first value of array?
What are all this warnings?
#include<stdio.h>
int main(void)
{
int *ptr = {1,2,3,4,5};//Is it not similar to char *ptr="Stackoverflow"?
printf("%d\n",*ptr);// why Segmentation fault(core dumped) instead of 1
return 0;
}
...
output:
warning: initialization makes pointer from integer without a cast [enabled by default]
int *ptr = {1,2,3,4,5};
^
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
//Is it not similar to char *ptr="Stackoverflow"?
TL;DR No, it is not.
The used initializer, {1,2,3,4,5} is called a brace-enclosed initalizer which is supposed to initialize the values of the type of the elements. This is used for aggregate or union type type, like mentioned as in C11, chapter §6.7.9, Initialization
the initializer for an object that has aggregate or union type shall be a brace enclosed
list of initializers for the elements or named members.
Here, the initializer list contains all int values, and you're trying to initialize a pointer thought it. This is wrong.
Also, regarding the scalar type, quoting C11, chapter §6.2.5
Arithmetic types and pointer types are collectively called scalar types.[...]
and the aggregate types
[...]Array and
structure types are collectively called aggregate types.
There are many issues here, like
You're using int value to initialize an int *.
You're ending up supplying a brace enclosed list containing more than one initializer element for a scalar object.
So, later in your code,
printf("%d\n",*ptr);
is essentially an invalid memory access, which invokes undefined behavior. The segmentation fault is one of the many side-effects.
Coming to the point of the comment,
char *ptr="Stackoverflow"?
In case of char *ptr="Stackoverflow";, here, "Stackoverflow" is called a string literal and ptr is initalized with the base address of the string literal.
Solution:
You need to have an array of ints which you can initialize using the brace-enclosed initializer. Something along the line of
int ptr[] = {1,2,3,4,5};
will be valid. Then you can use it like
for(int i = 0; i < 5; i++)
printf("%d\t", *(ptr+i));
Your original code is invalid. It contains at least two constraint violations: it provides initializers for objects that don't exist, and it tries to use an initializer 1 (of type int) for an int* object. A compiler could (and IMHO should) simply reject it. gcc is being overly permissive by compiling your code after merely warning about the errors. The resulting code has undefined behavior.
const char *cptr = "Hello";
The above is valid. "Hello" is an expression of array type (specifically of type char[6]). In most contexts, including this one, such an expression is implicitly converted to a pointer to the array's 0th element. Note that I've added const so the compiler will at least warn if I attempt to modify the data that cptr points to.
int *iptr = { 1, 2, 3, 4, 5 }; // invalid
This is invalid. You might expect that it's handled similarly to cptr. The problem is that { 1, 2, 3, 4, 5 } is not an expression; it's valid only in an initializer. It could be a valid initializer for an array object, but since it's not an expression, the array-to-pointer conversion rule doesn't apply.
Assuming your compiler supports C99 or later (specifically the compound literal feature), you can write:
int *iptr = (int[]){ 1, 2, 3, 4, 5 };
(This is not a cast; the syntax is similar, but the { ... } is not an expression.)
The compound literal is an expression of array type, specifically int[5], and the array-to-pointer conversion applies.
One caveat: A string literal creates an array object, and that object has static storage duration, meaning that it exists throughout the execution of the program. A compound literal creates an object with static storage duration only if it appears outside any function; inside a function, it creates an object with automatic storage duration, meaning that it ceases to exist when you reach the end of the current block. In this case, it's defined inside the main function, so it's not likely to be an issue. But it's something to watch out for. For example, this is safe:
const char *new_string(void) {
const char *result = "hello";
return result;
}
but this is not:
int *new_array(void) {
int *result = (int[]){ 1, 2, 3, 4, 5 };
return result; /* BAD! */
}
because the array ceases to exist when you leave the function. To avoid that, you can create the array object explicitly to make it static:
int *new_array(void) {
static const int arr[] = { 1, 2, 3, 4, 5 };
int *result = arr; /* or &arr[0] */
return result; /* or "return arr;" */
}
basically that line is invalid, the c compiler has tried to make sense of it but really cannot. You need the syntax here
How to initialize all members of an array to the same value?
Summary
int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
try:
#include<stdio.h>
int main(void)
{
int ptr[] = {1,2,3,4,5};//Is it not similar to char *ptr="Stackoverflow"?
printf("%d\n",*ptr);// why Segmentation fault(core dumped) instead of 1
return 0;
}
In the original code:
int *ptr = {1,2,3,4,5};
{1,2,3,4,5} won't initialize an integer array. String initialization is a special case which is not applicable over other types.
So this code will initialize an integer pointer which will point to memoery address 0x00000001 (first one in the initializer block)
This address is out of program scope and thus segmentation error came into picture.
Pointer is a scalar data type and standard says that (C11-6.7.9):
The initializer for a scalar shall be a single expression, optionally enclosed in braces.
You can't initialize a scalar data type with brace enclosed initializer having more than one expressions.
In case of
char *ptr="Stackoverflow";
ptr is pointing to the object with type array of char (look at standard C11:§6.7.9/11). It just initializes ptr to the start of the address of string literal.
You are trying to store values in an unitialised pointer. The value of the pointer must be attached to a memory location prior you can access it.
Just do some malloc before:
int $ptr;
ptr = malloc( 5* sizeof(int)); // since you have 5 values and then you can initialize your data
for (i=0;i<5;i++) {
(*ptr+i) = (i+1);
}
This question already has answers here:
Initializing variable length array [duplicate]
(3 answers)
Variable-length arrays in C89?
(3 answers)
Closed 8 years ago.
#include<stdio.h>
main() {
int a=5;
int array[a]={0};
printf("Success\n");
}
when i am executing the program it will through a error as
b.c: In function ‘main’:
b.c:8:1: error: variable-sized object may not be initialized
b.c:8:1: warning: excess elements in array initializer [enabled by default]
b.c:8:1: warning: (near initialization for ‘array’) [enabled by default]
In cc complier . but i can assign like this
int array[5]={0};
If anyone correct me?
This statement
int array[a]={0};
declares a Variable Length Array (VLA).
According to C Standard (6.7.9 Initialization)
3 The type of the entity to be initialized shall be an array of
unknown size or a complete object type that is not a variable length
array type.
The problem is that the compiler shall know the array size at compile time that to generate the code that initialize an array.
Consider an example
void f( size_t n )
{
int a[n] = { 1, 2, 3, 4, 5 };
//...
}
Here is a is a variable length array. Now as n can have any value then the number of initializers in the array definition can be greater than the size of the array. So this code breaks the Standard from another side because the number of initializers may not be greater than the number of elements of array. On the other hand if the number of initializers less than the number of elements of array then what to do in this case? Maybe the programmer did not mean that some elements shall be zero-initialized.
As for this declaration
int array[5]={0};
then there is no variable length array. The size of the array is known at compile time. So there is no problem
.
"Variable-length automatic arrays are allowed in ISO C99, and as an
extension GCC accepts them in C90 mode and in C++"
says here.
Compilers can differ in some situations. It's normal to have problems with variable-sized arrays. This should work if you really need to do this
#include<stdio.h>
#DEFINE A 5
main()
{
int array[A]={0};
printf("Success\n");
}
The elements field within square brackets [], representing the number of elements in the array, must be a constant expression, since arrays are blocks of static memory whose size must be determined at compile time, before the program runs.
I declare a variable 'ptr' like this:
int array[4][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
int n = 4;
int (*ptr)[n] = (int (*)[n])array[0];
When put it in global,I got a error when compile the program:
error: variably modified ‘ptr’ at file scope
int (*ptr)[n] = (int (*)[n])array[0];
^
but it will be successful,when I put it in local.
btw:I use the gcc compiler.
Variables with variably modified type are only permitted at block scope (i.e. inside a function).
Variably modified type means an array type where one of the dimensions is not known at compile-time, or any type derived from that (e.g. pointer to such an array, as in your example).
int (*ptr)[n] has variably modified type because n is not a constant expression. For historical reasons, const int n = 4; would not count as a constant expression either. But #define n 4 would be a constant expression.
One workaround is to write:
int (*ptr)[ sizeof array / sizeof array[0] ] = &array[0]; // note: no cast required
Background: Variably modified type was added in C99, to support arrays whose dimension are not known until runtime.
Although actually using such an array is risky due to stack overflow, this syntax enables some nice follow-on effects. For example, the ability to use array syntax with malloc'd arrays, and the ability to have a function which can operate on a multi-dimensional array using array syntax; but accept various sizes of array.
For rationale as to why they are not permitted at file scope, see the answers to this question. (Currently that question is incorrectly closed as duplicate, but the answers are good)