What does the code below print when running the function print_test()?
struct test {
int a, b, c;
};
void print_test(void) {
struct test t = {1};
printf("%d/%d/%d", t.a, t.b, t.c);
}
Solution 1\0\0
Why are b and c initialized to zero even though I did not do it? Are there any default values for the struct?
However, the struct is not global and the member is not static. Why are they automatically zero-initialized? And if the data type were not int another data type to which value will be initialized?
If you don't specify enough initializers for all members of a struct, you'll face Zero initialization, which will initialize remaining members to 0. I think by today's standards this seems a bit odd, especially because C++'s initialization syntax has evolved and matured a lot over the years. But this behavior remains for backwards-compatibility.
I think we need to know two points at this stage:
There is nothing different between regular variables and structs, if they are at local scope i.e automatic storage duration. They will contain garbage values. Using those values could invoke undefined behaviour.
The only thing that makes structs different is that if you initialise at least one of the members, the rest of the members will get set to zero i.e. initialised as if they had static storage duration. But that's not the case when none of the members are initialised.
It depends on your declaration.
If your declaration is outside any function or with the static keyword (more precisely, has static storage duration), the initial value of x is a null pointer (which may be written either as 0 or as NULL).
If it's inside a function i.e. it has automatic storage duration, its initial value is random (garbage).
consider the following code:
#include<stdio.h>
#include<unistd.h>
struct point {
int x, y;
char a;
double d;
};
typedef struct point Point;
void main(){
Point p1;
printf("\nP1.x: %d\n", p1.x);
printf("\nP1.y: %d\n", p1.y);
printf("\nP1.a: %d\n", p1.a);
printf("\nP1.d: %lf\n", p1.d);
Point p2 = {1};
printf("\nP2.x: %d\n", p2.x);
printf("\nP2.y: %d\n", p2.y);
printf("\nP2.a: %d\n", p2.a);
printf("\nP2.d: %lf\n", p2.d);
}
The output is :
P1.x: 0
P1.y: 66900
P1.a: 140
P1.d: 0.000000
P2.x: 1
P2.y: 0
P2.a: 0
P2.d: 0.000000
A Good read: C and C++ : Partial initialization of automatic structure
Related
#include <stdio.h>
typedef struct
{
int a;
int b;
}my_struct;
void check (my_struct *my_check)
{
printf ("%d\n", my_check->a);
}
int main()
{
//block with local variables
{
int a = 2;
printf("int inside block %d\n", a);
my_struct m1;
m1.a = 2;
printf ("my_struct m1 inside block\t");
check (&m1);
}
//outside the block; so the variables and their values inside the above block is outside the scope of the following code
int a;
printf("int outside block %d\n", a);
my_struct m2;
my_struct m1;
printf ("my_struct m1 outside block\t");
check (&m1);
printf ("my_struct m2 outside block\t");
check(&m2);
return 0;
}
The above piece of code will output
int inside block 2
my_struct m1 inside block 2
int outside block 0
my_struct m1 outside block 2
my_struct m2 outside block 522062864
My question is:
Why "int a" inside the block was not accessible with a variable of same name i.e. int a, but "my_struct m1" was?
My understanding is, if it is outside the block, then it is fresh declaration and definition. New assignment is needed for variables outside, else they will contain default/garbage values
You are in the world of Undefined Behaviour. You have created some variables in the inside block. Fine. Then when you exit the block, those variables vanish. You now create different variables in the outside. And you try to use those uninitialized variables which is explicitely Undefined Behaviour.
That means that what happens could be different from one system to another one, or on the same system with different compilation options, or even on different runs. And anyway, you should never rely on that consistently happening.
Now what actually happens in that system and in that specific run: your implementation probably uses the stack for the structures and registers for single values for which you never use an address. So when you create a new single variable it receives what was in a register and could be anything. But when you create a new struct it just reuses the memory that has just be released by the previous one, and you get the old value. But as I have already said you cannot rely on that.
struct forces{
double fo[1];
double ft[1];
};
int main(void){
struct forces frc;
frc.fo[0]=6;
frc.fo[1]=56;
frc.ft[0]=567;
printf("%.0lf\n",frc.fo[1]);
return 0;
}
Please assist. Why is my printout always frc.ft[0]?
With your declaration, fo[1] does not exist and writing to it is undefined behavior for C and C++.
Change your declaration to this to make fo[1] a valid element
struct forces{
double fo[2];
double ft[1];
};
In C and C++ (and most similar languages) a declaration of foo[5] creates a 5-element array with valid index values of [0] ... [4]. int foo[1] only has a valid index foo[0]
With your code you see fo[1] in place of ft[0] because your compiler placed the two double variables together in memory with no gap (padding) between them.
I am writing a data mashing function where I'm modifying audio data over time for a sort of dynamic bit-crusher audio filter. It is convenient for me to use static variables because their values carry over between function calls and this helps me achieve some interesting time-based effects by incrementing and so forth across rendering callbacks.
For example, one effect uses a sin function to modulate some sound effect over time. Like so:
void mangle(float * data, int n) {
static bool direction = false;
static float bottom = 0;
static float top = n;
static float theta = 0;
theta += 5;
// data = sin(theta) etc..
So I wish theta to be initialized once and than modified over time. Likewise, top wants to be static variable because I modify it later in the function also. In addition, top should take on the value of parameter n because n changes based on program state. But when I go to assign n to top, I get the compiler error
Initializer element is not a compile-time constsant.
Is there a way to assign a parameter to a static variable? Is there another way to accomplish what I want without static variables? I am aware I could use instance variables but I find that to be too much.
static variables are initialized before the program execution begins, so you cannot use a variable value to initialize a static variable. You'll need a compile-time constant value to initialize the static variable.
Quoting C11 standard, chapter §6.2.4, Storage durations of objects (emphasis mine)
[..] or with the storage-class
specifier static, has static storage duration. Its lifetime is the entire execution of the
program and its stored value is initialized only once, prior to program startup.
However, you can always assign a new value to the static variable.
That said, coming to the initialization part, as per chapter §6.7.9,
If an object that has static or thread storage duration is not initialized
explicitly, then
- ...
- if it has arithmetic type, it is initialized to (positive or unsigned) zero
- ...
so, you need not initialize the static floats explicitly to 0. You can assign any value, whatsoever later in the code.
In your case, top is a local static variable.
It is like global static variable and global variable that they all have static storage duration and they have value before the code startup.
The reason you have error similar to this case:
int a;
int b = a; \\initializer is not a constant
int main() {
...
}
With your purpose, use top as a global variable is a right way to go.
What you should do is create a struct that holds the data that is needed across calls and pass a pointer to the struct to the function. If you wnat to get fancy, you can create functions that allocate, initialize and free such a struct (and the user of the functions never needs to know what the contents of the struct are.
Something like:
struct mangle_t {
bool direction;
float bottom;
float top;
float theta;
};
struct mangle_t* mangle_open(void)
{
struct mangle_t* m = malloc(sizeof *m);
if (m) {
memset(m, 0, sizeof *m);
}
return m;
}
void mangle_close(struct mangle_t* m)
{
free(m);
}
void mangle(struct mangle_t* m, float * data, int n) {
m->top = n;
m->theta += 5;
}
As far as assigning a parameter to a static variable, you can just perofrm the assignment like any other variable (however, not as an initialization in the variable's declaration - that only happens once).
I'm not sure if you want to initialize top once and then keep it, but if so, this is what I would do:
void mangle(float *data, int n) {
static float top = -1; // Assuming that n will never be -1
if (top == -1)
top = n;
// .....
}
If you don't need to keep the value of top over function calls, there is no need to declare it static.
I recently learned that copying partially initialized structures through trivial construction or assignment is undefined in C++. Does the same hold true in C or does the standard guarantee that initialization and assignment behave like memcpy?
typedef struct { int i; int j; } A;
void foo() {
A x;
x.i = 0;
// Leave x.j indeterminate. Is the following well defined?
A y = x;
y.j = y.i + 1;
}
x is not "partially initialized" this is not initialized at all.
Reading x in your initializer for y propagates the "indetermined" valueness (if one can say so) to y. If int could have trap representations on your platform, this already would be an error.
But then you don't read that indeterminate field y.j, so there no problem at that particular assignment.
I'm wondering what's the difference between sample1 and sample2. Why sometimes I have to pass the struct as an argument and sometimes I can do it without passing it in the function? and how would it be if samplex function needs several structs to work with? would you pass several structs as an argument?
struct x
{
int a;
int b;
char *c;
};
void sample1(struct x **z;){
printf(" first member is %d \n", z[0]->a);
}
void sample2(){
struct x **z;
printf(" first member is %d \n", z[0]->a); // seg fault
}
int main(void)
{
struct x **z;
sample1(z);
sample2();
return 0;
}
First of all, your argument type is not struct, but a pointer to pointer to struct (or an array of pointers to struct - these are semantically equivalent from the callee's point of view, except that the address of an array can't be changed).
In the second case you use a local variable that is totally independent of the one with same name in main. Since it is not initialized, you get a seg fault when trying to access one of its members. (The one in main is not initialized either, but accessing it just seems to work by chance in sample1).
You should initialize your variables before using them, otherwise you enter the territory of undefined behaviour. E.g.
void sample1(struct x **z){
printf(" first member is %d \n", z[0]->a);
}
void sample2(){
struct x z[1];
z[0].a = 1;
...
printf(" first member is %d \n", z[0].a);
}
int main(void)
{
struct x z[1];
z[0].a = 1;
...
sample1(z);
sample2();
return 0;
}
Both are invalid and accessing bad memory. The results are undefined so both results are correct.
C and C-like languages have a concept of "scope". See all those curly braces ({ and })? Those are "blocks". They essentially wrap all the code between them into bundles that are independent of any other blocks at the same level. Any variable you create in that block is only accessible within that block—you can't reference it anywhere else.
You can create a nested block. For example:
int f() {
int x;
scanf("%d", &x);
if (x == 3) {
return 7;
}
else {
return x;
}
}
As you can see, the else block is nested inside the function's block, and so can access the function's variables.
When you declare struct x **z in both main and sample2, you're actually creating two variables, both called z. These are totally independent—they're not the same variable at all. They're not related. The only thing they have in common is their name and type—the actual value is different. The only way you can use the same variable in both is by passing, as you do in sample1.
Of course, currently, your z pointer is garbage—you haven't allocated anything. I'd recommend you actually store something in there before you try and dereference it.
Your declaration
struct x **z;
simply creates a pointer to a pointer to a structure of type x. You're not actually initialising the pointers, i.e. making them point anywhere.
Try something like
struct x z;
struct x *pZ = &z;
sample1(&pZ);
(I'm not completely sure what you're actually trying to achieve, though!)