Reputation: 403
By adding an extra *
within var variables[26];
, I can avoid mixing .
and ->
and use the same operator ->
in all codes. My classmate suggested that I might be wasting extra memory, but it did smoothen my coding experience as I make less mistakes.
Is this considered bad practise or acceptable?.
Original version
#include <stdio.h>
struct var {
int ** num;
int y;
int x;
int count;
};
typedef struct var var;
struct prog
{
var variables[26]; <===================================BEFORE CHANGE
};
typedef struct prog prog;
int main()
{
prog *p = calloc(1,sizeof(prog));
//p->variables[0] = calloc(1, sizeof(var));
p->variables[0].y=1; <========================= BEFORE CHANGE, USING '.' to access y
return 0;
}
Changed version
#include <stdio.h>
struct var {
int ** num;
int y;
int x;
int count;
};
typedef struct var var;
struct prog
{
var* variables[26]; <===================================Added * after var
};
typedef struct prog prog;
int main()
{
prog *p = calloc(1,sizeof(prog));
//p->variables[0] = calloc(1, sizeof(var));
p->variables[0]->y=1; <=========================== Now can use '->' instead of '.'
return 0;
}
Upvotes: 2
Views: 80
Reputation: 26355
var* variables[26];
allocates memory for 26 pointer-to-var objects. It does not allocate any memory for the var
objects themselves. As is, your second example program has Undefined Behavior by attempting to dereference a null pointer.
You need the commented out line (and possibly 25 more like it)
p->variables[0] = calloc(1, sizeof(var));
as this is what allocates memory for the structure itself.
The use of automatic vs dynamic memory changes for every use case. Unless stack memory is a concern, in this case you are doing more work, and introducing more points of failure into your program.
My classmate suggested that I might be wasting extra memory
You are using 26 * sizeof (var *)
extra bytes of memory in the second example.
I can avoid mixing . and -> and use the same operator -> in all code.
There will be plenty of times when you will be forced to mix both, and you should get used to both operators. They are both equally important, and having a solid understanding of both will benefit you greatly.
Arbitrary counter argument: Why not use automatic storage and .
for everything?
#include <stdio.h>
typedef struct var {
int **num;
int y;
int x;
int count;
} var;
struct prog {
var variables[26];
};
typedef struct prog prog;
int main(void)
{
prog p = { 0 };
p.variables[0].y = 1;
for (size_t i = 0; i < 26; i++)
printf("%d\n", p.variables[i].y);
}
The answer again, is that sometimes you can (here; ignoring the num
structure member and its intended use), and sometimes you cannot (large allocations, complicated allocations, external allocations).
Upvotes: 2
Reputation: 31389
Firstly, you have made some mistakes in the conversion. But that's not the main issue.
There are certainly situations where a pointer with dynamic allocation is preferred instead of an array. But I would not say that doing the switch only to be able to type ->
instead of .
is a good reason. As a C programmer, you're expected to be able to cope with both.
Is this considered bad practise or acceptable?
I would NEVER accept if someone refactored code for this particular purpose.
Upvotes: 2
Reputation: 540
prog->variables in your second code is an array of var*
. You can't just write prog->variables[0]->y
as variables[0]
has not been allocated, you have to call malloc or calloc on every element inside the array.
Upvotes: 2