This question already has answers here:
Can a const variable be used to declare the size of an array in C?
(5 answers)
Closed 4 years ago.
I've found an interesting fact, and I didn't understand how is it works.
The following piece of code just works perfectly.
#include <stdio.h>
int main(){
const int size = 10;
int sampleArray[size];
typedef char String [size];
return 0;
}
Then, I tried to use only and only the constant variable with a global scope, and it's still fine.
#include <stdio.h>
const int size = 10;
int main(){
int sampleArray[size];
typedef char String [size];
return 0;
}
But, if I change the arrays's scope to global as well, I got the following:
error: variably modified ‘sampleArray’ at file scope
#include <stdio.h>
const int size = 10;
int sampleArray[size];
typedef char String [size];
int main(){
return 0;
}
And I didn't get it! If I'd replace the const variable for ex. to #define it'd be okay as well.
I know that the #define variable is preprocessed, and as far as I know the const variable is only read-only. But what does make the global scope after all?
I don't understand what is the problem with the third piece of code, if the second one is just okay.
Variable Length Arrays may have only automatic storage duration. VLAs were introduced in C99.
It is not allowed to declare a VLA with the static storage duration because the size of VLA is determinated at the run time (see below)
Before this Standard you can use either a macro like
#define SIZE 10
//...
int a[SIZE];
or a enumerator of an enumeration like
enum { SIZE = 10; }
//...
int a[SIZE];
By the way you may remove the const qualifier and just write
int size = 10;
instead of
const int size = 10;
(In C++ you have to use the const qualifier though in C++ there are no VLAs except that some compilers can have their own language extensions)
Take into account that the sizeof operator for VLAs is calculated at the run-time instead of the compile-time.
Related
I use the const for assigning the variable but the array shows an error "variable-sized object may not be initialized"
#include <stdio.h>
int main()
{
const int city=10;
const int week=2;
int arr[city][week]={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
for(int i=0;i<city;i++)
{
for(int j=0;j<week;j++)
{
printf("%d",arr[city][week]);
}
}
}
You are using const qualified variables for your array dimension and not "integer constant expressions". For C, this means that your array is a variably modified type, for which C does not allow initializers.
As others already told you, if initialization would be allowed, the syntax has to be = and not ==.
You have several issues.
you've posted it in the subject, is that you can't use const int for the array length and then initialize it, because it will become a variable-sized object, and you can't initialize it in with constant numbers. You can use #ifdef to define city/week, and then it will not happen.
You've used compare (==) instead of assignment (=)
change:
int arr[city][week]=={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
to:
int arr[city][week]={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
you need to change your printf and probably add line break:
printf("%d\n",arr[i][j]);
so to summarize:
#include <stdio.h>
#define city 10
#define week 2
int main()
{
int arr[city][week]={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
for(int i=0;i<city;i++)
{
for(int j=0;j<week;j++)
{
printf("%d\n", arr[i][j]);
}
}
}
== compares, = assigns
you even would print the same output
i would also prefer to use {a,b},{c,d}...
I have recently run into some trouble while trying to perform the following logic:
static const int size = getSize();
int getSize() {
return 50;
}
The error I have received is initialiser element is not constant
Having read online I understand that this issue is because the compiler evaluates the static const expression at compilation and therefore cannot know what the value is supposed to be.
My question is how do I get around this?
If I have a library that contains many functions but they all require this logic how are they supposed to use it without having to calculate it each time?
And even if they have to, what if the logic itself can change throughout runtime but I only ever want the first value I receive from the function?
Perhaps I should clarify that the logic in getSize is just an example, it could also contain logic that retrieves the file size from a specific file.
Unlike in C++ you cannot initialize global variables with the result of a function in C, but only with real constants known at compile time.
You need to write:
static const int size = 50;
If the constant must be computed by a function you can do this:
Dont declare static const int size = ... anymore, but write this:
int getSize()
{
static int initialized;
static int size;
if (!initialized)
{
size = SomeComplexFunctionOfYours();
initialized = 1;
}
return size;
}
int main(void)
{
...
int somevar = getSize();
...
That way SomeComplexFunctionOfYours() will be called only once upon the first invocation of getSize(). There is a small price to be paid: each time you invoke getSize(), a test needs to be performed.
Or you can initialize it explicitely like this, but then size cannot be const anymore:
static int size;
void InitializeConstants()
{
size = SomeComplexFunctionOfYours();
}
int main(void)
{
InitializeConstants();
...
int somevar = size;
...
The compiler needs to know the value of your constant variable at the compilation time, because its a constant.
Also you can't initialize a variable with a function.
You should do something like this :
#define SIZE 50
static const int size = SIZE;
I am trying to do the following but am getting the following error:
"error: expected expression before { token
Test_Stubs.h
#define SIGNATURE 0x78,0x9c
Test.c
#include "Test_Stubs.h"
static unsigned myArray[100];
static void
setup(void)
{
myArray = {SIGNATURE};
}
EDIT
Follow on question:
Is there a way to assign the individual values in the #define to specific indexes of myArray? For instance...
#include "Test_Stubs.h"
static unsigned myArray[100];
static void
setup(void)
{
myArray[0] = SIGNATURE[0]; //0x78
myArray[1] = SIGNATURE[1]; //0x9c
}
Clearly the above code will not code as SIGNATURE is neither an array or pointer.
As per the C syntax rules, you can only initialize an array using a brace enclosed initializer list at the time of definition.
Afterwards, you have to initialize element by element, using a loop, or, if you need to initialize all the elements to the same value, you can consider using memset().
EDIT:
No, as I mentioned in my comments, as per your code snippet, SIGNATURE is neither an array name, nor represent any array type, so you cannot use indexing on that.
However, using compound literal (on and above C99), if you change your #define, then, somehow, you can make this work. See the below code for example,
#include <stdio.h>
#define SIGNATURE ((unsigned [100]){0x78,0x9c})
static unsigned myArray[100];
int main (void)
{
myArray[0] = SIGNATURE[0]; //0x78
myArray[1] = SIGNATURE[1]; //0x9c
return 0;
}
See a LIVE VERSION
I have the following declaration inside a function
int f[20000]
I want the number 20000 to be dynamic, How can i declare such array in code?
To be more specific, I have the following code to calculate PI.
#include <stdlib.h>
#include <stdio.h>
#define BITS 2000
int a=10000,b,c=BITS*7/2,d,e,f[BITS*7/2+1],g;
int main()
{
for(;b-c;)
f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)
for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);
//getchar();
return 0;
}
I changed to
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
//
// .... omit some lines here
// read bits from user input at runtime
// say precision = 200
//
int a=10000,b,c=precision *7/2,d,e,f[precision *7/2+1],g;
for(;b-c;)
f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)
for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);
//getchar();
return 0;
}
It doesn't work, I googled then changed to
int a=10000,b,c=precision *7/2,d,e,g;
int *f=calloc(precision *7/2+1, sizeof(int));
It still doesn't work, I mean the program doesn't crash, the value it calculated is not correct. What's wrong? Thank you.
There are two ways to achieve what you want.
use dynamic memory allocation. malloc()/calloc()
use variable-length array (in c99)
That said, as pointed out by #user3386109, the problem in your second code snippet is use of uninitiated variable b. You may want to explicitly initialize the local variables before using their value.
You get a dynamically sized array by allocating on the heap using malloc (or calloc).
Replace
int f[20000];
with
int *f = (int *) malloc(20000 * sizeof(int) );
The difference is that global variables are guaranteed to be initialized to 0 (unless initialized to some other value). But local variables are garbage unless you initialize them. So the problem is that variable b starts out as garbage in the second snippet.
In the original code:
int a=10000,b;
int main(void)
{
}
a will start with the value 10000 because you initialized it, and b will start as 0 because it is an uninitialized global variable.
In the changed code:
int main(void)
{
int a=10000,b;
}
a will start with the value 10000 because you initialized it, and b will start as some random value (e.g. 0x5315fe) because it is an uninitialized local variable.
Replace int f[2000]
with
int *f = new int[2000];
then use the array as f[0] = 1, f[1] = 2 etc...
when finished free up memory with delete [] f;
the array size could be allocated by a variable
eg.
int x = 2000;
f = new int[x];
Below I have to examples of code that do the same thing and give the same output. In the first, I use pointer to pointer argument passing to eliminate the use of ans as a global. In the second, I madeans a global which eliminated the additional uses of * when dealing with pointer to pointer:
Example 1:
// pointer to pointer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
unsigned char serial[] = {
0x1,0x2,0x3,0x4
};
void checkSerial(unsigned char* buf, unsigned char ** ans)
{
int i;
unsigned char *part;
part = 0;
i=2;
part = &buf[i];
*ans = (unsigned char*)malloc(2);
memset(*ans,0,2);
memcpy(*ans,part,2);
printf("0x%x\n",**ans);
++(*ans);
printf("0x%x\n",**ans);
}
int main(void)
{
unsigned char *ans, *buf;
while(1)
{
buf = malloc(4);
memset(buf,0,4);
memcpy(buf, serial, sizeof(serial));
checkSerial(buf, &ans);
--ans;
printf("the value is 0x%x\n", *ans);
free(buf);
free(ans);
sleep(3);
}
return 0;
}
Example 2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
unsigned char serial[] = {
0x1,0x2,0x3,0x4
};
unsigned char ans[2];
void checkSerial(unsigned char* buf)
{
int i;
unsigned char *part;
part = 0;
i=2;
part = &buf[i];
int j;
for(j=0;j<2;j++)
{
ans[j] = part[j];
}
printf("0x%x\n",*ans);
++(*ans);
printf("0x%x\n",*ans);
}
int main(void)
{
unsigned char *buf;
while(1)
{
buf = malloc(4);
memset(buf,0,4);
memcpy(buf, serial, sizeof(serial));
checkSerial(buf);
printf("the value is 0x%x\n", *ans);
free(buf);
sleep(3);
}
return 0;
}
Which technique is preferred in C?
Avoid global variables when it is not necessary. Going with first example is preferable.
Global variables are easily accessible by every functions, they can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
Keep variables as close to the scope they are being used in as possible. This prevents unexpected values for your variables and potential naming issues.
I personally don't like defining global variable where there is ways to avoid it.
But some guys say that, the concept of pointer is very much confusing. I don't feel that though..
My advice, if you get confuse with pointers try to avoid it with defining global variable. Otherwise, use pointers... :)
TL;DR: Solutions 1 and 2 are both bad.
The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time, if those are really known at compile-time then , just don't use malloc at all, declare variables on the stack. In C, generally avoid dynamic memory allocation as much as possible and prefer to create buffers which can hold the maximum size a buffer can have in your application. That avoids this kind of problems in the first place. The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time. The only place where dynamic memory allocation can be useful is for buffers whose sizes are unknown at compile-time, but you can still avoid it (see below). If buf is an incoming message, and ans the answer to this message, the size of ans can be unknown at compile-time, at least if you use variable-length messages.
Your version 2 is not working and can not work! First you declared ans to be an array of size 1 and iterate over it until index 2(now you edited that). Second to declare the array ans as global you would need to know its size at compile-time, and then of course if you knew its size at compile-time you would just declare the array ans in the function checkSerial. Moreover, when you declare a variable which is used by several functions in C don't forget to declare it static, otherwise it can be accessed from all files in your project.
A solution avoiding dynamic allocation, notice you avoid the disadvantages of your 2 solutions: the pointer to pointer and the global variable, and moreover your program can not leak since you don't use dynamic allocation:
enum {MSG_MAX_SIZE = 256 };
typedef struct message {
uint8_t payload[MSG_MAX_SIZE];
size_t msg_size;
} message_t;
void checkSerial(const message_t *buf, message_t *ans)
{
//parse buf and determine size of answer
...
...
//fill answer payload
ans->msg_size = buf[42];
}
int main(void)
{
while (1) {
message_t buf;
getMsg(&buf);
message_t ans;
checkSerial(&buf, &ans);
}
}