Confusing about the scope of the variables in C - c

Code 1
#include <stdio.h>
int T;
int main()
{
struct T{ double x;};
printf("%d", sizeof(T));
return 0;
}
Output: 4
Code 2
#include <stdio.h>
struct T{ double x;};
int main()
{
int T;
printf("%d", sizeof(T));
return 0;
}
Output: 4
For the code 1, I think that the output is the size of the global variable(int T) that's why it gives 4.
But for the code 2, it gives output 4, according to the global variable logic, it should be output 8 for struct T{ double x;};.
Here, the global variable concept is not correct - I think.
Can anyone please explain this why the output looks like?

The problem here isn't the scope but how structures tags live in a different namespace than other symbols.
Because of this when you do sizeof(T) you always get the variable T.
To get a structure tag in C you need the struct keyword. As in sizeof(struct T).
Things would be different if you used typedef:
struct T
{
double x;
} T;
Then you would have a type named T in the "normal" namespace. On the other hand that type would conflict with the variable with the same name so you would get a compiler error instead.

Related

The right way of implementing a constructor in C

I want to create a constructor using C.
What is the cleanest way to achieve this?
My attempt:
#include <stdio.h>
struct line {
void (*add_line_ptr)(struct line*, int x, int y);
int x;
int y;
};
void add_line(struct line* lptr, int x, int y)
{
lptr->x = x;
lptr->y = y;
}
int main()
{
struct line line1 = {add_line, 0, 0};
line1.add_line_ptr(&line1, 10, 20);
printf("%d %d\n", line1.x, line1.y);
}
I think that using line1.add_line(&line1, is a bit redundant - since it's quite obvious that I want to do the operation on line1.
Is there a way to implement this without passing a pointer to the "object"(struct)? or some other way I didn't think of?
Using function pointers just for the sake of emulating C++-like syntax is just messy with no obvious benefits. You won't have RAII in C no matter what you do, so you need to call constructors/destructors explicitly. If you do so by typing obj.foo() or obj = foo() has absolutely nothing to do with OO, it's mere coding style.
The main problem here though, is that your code does not have proper OO design, since the struct is completely open and not using private encapsulation. For the same reason as class line { public: int x; int y; }; is not proper OO either - you don't get OO just because you smash some related variables into an aggregate type, regardless of language.
"Cleanest"/"prettiest" would mean full private encapsulation. In C, that can be achieved with opaque types. I prefer to implement them without hiding pointers behind typedef, so:
line.h
#include <stdio.h>
#include <stdlib.h>
typedef struct line line; // forward declaration of incomplete type
line* line_construct (int x, int y);
line.c
#include "line.h"
struct line { // actual definition of the struct, local to line.c
int x; // private variable
int y; // private variable
};
line* line_construct (int x, int y)
{
line* obj = malloc (sizeof *obj);
if(obj == NULL) { /* error handling here */ }
obj->x = x;
obj->y = y;
return obj;
}
caller.c
#include "line.h"
int main(void)
{
line* x = line_construct(10, 20);
}
Here line is 100% encapsulated and the contents of the struct cannot be accessed by the caller. Since I don't hide pointers behind typedef, the caller must always use line* pointers and can never declare an instance of the object directly.
If the constructor is only meant to zero-out the struct members, then it doesn't need to get passed any parameters but can do so internally.
And obviously you need to implement a corresponding destructor with free as well.
line* line_destruct(line* obj) { free(obj); return NULL; } or so.
I wouldn't put the initializer into your structure to begin with. Other functions, sure, but not the first one. Something like this:
#include <stdio.h>
struct line {
int x;
int y;
};
void add_line(struct line *lptr, int x, int y)
{
lptr->x = x;
lptr->y = y;
}
int main()
{
struct line line1 = {0, 0};
add_line(&line1, 10, 20);
printf("%d %d\n", line1.x, line1.y);
}
The reason is that you have to assign the initializer anyway after you allocate your structure, either implicitly or explicitly. In OOP languages you normally name the class you want once, and both the allocator and initializer will run. In C you have to run them separately. Whether you allocate an object on the stack or on the heap, you will have to explicitly name the function you want to call at least once anyway.

Defining global struct array of pointers

im learning c programing.
I want to define a global struct array of. so I would have a pointer to that array that each member of the array is a struct of complex numbers.
my goal is to be able to acces to this array by his pointer (*vars) and being able to change/read its members on every function at the main.
Im facing troubles with this issue and im not sure how and where to define each thing.
I tried this next code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct complext
{
double real;
double img;
} complex;
complex* vars;
int main()
{
int i;
vars = malloc(6 * sizeof(vars));
for (i = 0; i < 6;)
vars[i]->real = 0;
}
Im getting an error when im trying to acces vars[i].
"request for member 'real' im something not a structure or a union.
Thanks!
There are 3 bugs in your code
1. vars[i]->real should be vars[i].real. Pls honor the data-types You have defined vars to be a global pointer to the complex structure. To define it as an array use: complex vars[6]; --> Look at #José Fonte 's ans
2. malloc returns a void * cast it to (complex*) --> I learnt this should be ok (look at comments posted by #Stargateur)
3. The for loop at the end has no inc statement for i hence it runs forever
4. The malloc only allocates 6 pointer worth of memory (which is 6*sizeof(int)) since vars is a pointer of type complex. sizeof(vars) should be sizeof(complex) --> #xing pointed this out
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
typedef struct complext {
double real;
double img;
}complex;
complex *vars;
int main()
{
int i;
vars= (complex*)malloc(6*sizeof(complex));
for(i=0;i<6; i++)
vars[i].real=0;
}
Your mixing pointers with arrays. Doing it as an array (as a pointer already done by #Zakir):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
typedef struct complext {
double real;
double img;
}complex;
complex vars[6];
int main()
{
int i;
for(i=0;i<6;i++)
vars[i].real=0;
}
vars is of type struct complext *, but vars[i] is of type struct complext, so you just have to use vars[i].real instead of vars[i]->real.

Initialization of an array in a structure

I have declared 2 structure :
typedef struct
{
int a;
int b;
}ma_Struct;
typedef struct
{
int x;
ma_Struct tab[2];
}maStruct_2;
The goal is to initialise an instance of maStruct_2 so what i did is:
int main()
{
ma_Struct elm1={0,1};
ma_Struct elm2={1,2};
ma_Struct tab_Elm[2]={elm1,elm2};
maStruct_2 maStruct_2_Instance={1,tab_Elm};
return 0;
}
but i got the warning missing braces around initializer,i tried this syntax
maStruct_2 maStruct_2_Instance={1,{tab_Elm}};
but the same warning appears.
Could you please help me
In C, you cannot initialize an array by using another array name as initializer.
So the error has nothing to do with structs as such, nor does it have anything to do with scope or constant expressions.
Fix your code like this:
maStruct_2 maStruct_2_Instance = {1, {elm1, elm2}};

New to programming, issue with structures and functions

Hey I'm new to programming (learning through cs50x in C) and when they mentioned structures I decided to try to fool around and just write a quick program that would swap some values in a structure using a function. I'm running until several error messages, the first of which is "incompatible pointer types passing 'struct numbers*' to parameter of type 'struct numbers*'. Another issue seems to come up in the function definition where the compiler says "incomplete definition of type 'struct number'" I was just hoping for some help cause I'm stumped.
Heres the code (I know its rough but I'm learning lol)
#include <stdio.h>
struct numbers;
void swap(struct numbers* s);
int main(void)
{
struct numbers
{
int a;
int b;
int c;
};
struct numbers x = {1, 5 , 9};
swap(&x);
printf("%i, %i, %i\n", x.a, x.b, x.c);
return 0;
}
void swap(struct numbers* s)
{
int temp = s -> a;
int temp2 = s -> b;
s -> a = s -> c;
s -> b = temp;
s -> c = temp2;
}
You're expecting the code in swap() to be able to access the fields of struct numbers, but the full declaration of that type is inside main(), so it's not visible.
Break out the declaration, it must be visible to all who need it. Putting it first will also remove the need to pre-declare the structure.
The same with swap() itself, putting it before main() will remove the need to have a prototype for it in the same file.
It should be:
struct numbers
{
.
.
.
}
static void swap(struct numbers *s)
{
.
.
.
}
int main(void)
{
.
.
.
}
The problem is that the struct numbers declaration is global, but the definition is local in main, To use the members of a structure, the swap function must know what members the structure have, and as it can't see the definition it doesn't know that. Remove the declaration and put the definition in the global scope.
Function swap can't see the definition of struct numbers. Put it globally outside main.
Extra Tip - Use typedef with structs, it gives you flexibility in declaration:
typedef struct typeNumbers
{
int a;
int b;
int c;
} numbers;
Note that typeNumbers is optional. Declare it like:
numbers x = {1, 2, 3};
The problem was that the structure was in main, I did some fixes also to the code and comment them.
#include <stdio.h>
//By defining the struct at the beginning you can avoid the forward declaration
//and it make more sense to know what "numbers" is before continuing reading the code.
struct numbers {
int a;
int b;
int c;
};
void swap(struct numbers* s)
{
//Small change to use only one temp variable...
int temp2 = s -> b;
s -> b = s -> a;
s -> a = s -> c;
s -> c = temp2;
}
int main(void)
{
struct numbers x = {1, 5 , 9};
swap(&x);
printf("%i, %i, %i\n", x.a, x.b, x.c);
return 0;
}

Is something like "typedef int arrChoice[5];" a global variable?

#include <stdio.h>
#include <conio.h>
typedef arrChoice[10] /*is this a global variable?*/
int main() {};
getch();
return 0;
}
its not done yet, but this is what i meant.
typedef is not a global variable, it's simply an alias for another type. I usually use them for function pointers when I'm passing those around because writing them out every time is annoying.
typedef int (*function)(int, int);
I also use them to define a structure, union, or enumeration as a type
typedef struct {
int x;
int y;
int z;
} Point;
typedef declares the new type not variable.
This might help you. In the code you posted here, there is a error. There are no statements in side main function. getch and return statements should be inside main function. I feel your code should be like this.
#include <stdio.h>
typedef int arrChoice; /* arrChoice is alias to int */
arrChoice a[10] ;/* array a is a global variable of integers*/
int main()
{
getch();
return 0;
}
please note that the purpose of typedef is to assign alternative names to existing types(int,float,double,etc.). The following statements are similar.
typedef arrChoice[10] is similar to typedef int[10];
When you try to refer arrChoice, then you get an error message
expected expression before 'arrChoice'.

Resources