How to set size of nested structure? - c

I'd like to make a simple database without making a dynamic sized array. I thought nested structure can help me, but so far it's nothing but pain. This was my idea when I started:
#include <stdio.h>
#define MAXDOG 50
#define MAXCHAR 20
struct allDog {
int size;
struct oneDog[MAXDOG] {
char dogName[MAXCHAR];
char OwnerName[MAXCHAR];
};
};
I'm pretty sure that my problem is the [MAXDOG] part after struct oneDog, can I give a static size somehow to the inner structure?
You can read the part of the exam I try to do below:
The program asks for the Dog's & Owner's name (MAX 50) then prints out the data. You can't use dynamic arrays...

You're overcomplicating things - try this:
#define MAXDOG 50
#define MAXCHAR 20
typedef struct { // struct which defines one dog
char dogName[MAXCHAR];
char ownerName[MAXCHAR];
} Dog;
typedef struct { // struct which contains array of dogs
int size; // no of dogs in array currently
Dog dogs[MAXDOGS]; // array of up to MAXDOGS dogs
} Dogs;

You sized the type not the member, syntax is:
struct allDog { // type
int size;
struct oneDog { // type
char dogName[MAXCHAR];
char OwnerName[MAXCHAR];
} dogs[MAXDOG]; // member
};
Take care to be consistent with caps in naming, member OwnerName should be written ownerName to be consistent with other members. Types are generally typed AllDog and OneDog, to differentiate in between members and types.

Related

How to call member of a struct using string declaration as representation of the actual member? [duplicate]

This question already has answers here:
Reflection support in C
(10 answers)
Closed 3 years ago.
My goal is to call a member of a struct without using the actual member. It sounds confusing but here's my sample code for further explanation:
#include <stdio.h>
#include <conio.h>
#include <string.h>
typedef struct record
{
char name[50];
}REC;
int main()
{
REC r;
char input[50] = "name"; //goal is to access r.name
char test1[50] = "Successful!";
r.input = test1; //This returns an error obviously
}
I declared char input to "name" as one of REC struct members. When compiled, error returns with "REC has no member named 'input'". How can i use 'input' to call one of rec struct members? Thank you in advance.
Like this, basically:
if (!strcmp(input, "name"))
strcpy(r.name, test1);
else
printf("Invalid field!\n");
C does not provide a way to access struct fields based on their name.
Perhaps you can think of more clever ways to write the above code, but whichever way you do it, you'll need to write a list of all the possible fields yourself.
I didn't figure out your goal. It seems that you want the member name of struct variable. But the member name if fixed when you define the struct. I only image maybe you have several different struct define. In that case, you can set struct member's value as following:
#include <stdio.h>
#define STR_SET(str,m,v) (str.m=(v))
#define MEM1 name
#define MEM2 age
typedef struct
{
char* name;
}REC_1;
typedef struct
{
char* age;
}REC_2;
int main(void)
{
REC_1 r1;
REC_2 r2;
char test1[50] = "Successful!";
STR_SET(r1, MEM1, test1);
STR_SET(r2, MEM2, test1);
}

C newbie: can I have fixed-size dynamically allocated structs? [duplicate]

I have a task to do and the content of the task is:
Please suggest a definition of linked list, which will keep the person's name and age in a flexible structure. Then write the procedure for inserting elements with the given name and age.
What exactly is a flexible structure? How to define it? And then how to malloc the size?
typedef struct Test {
int age; // ?
char name[?]; // ?
struct Test * next;
}Structure;
int main(void) {
Structure *one = malloc(???);
}
You are on the right track. However, there is no "flexible structure". You want to use a flexible array member (avail since C99) in a struct:
typedef struct {
int age;
size_t name_size; // size of the array, not length of the name!
char name[]; // Flexible array member
} Structure;
int main(void) {
Structure *one = malloc(sizeof(*one) + SIZE_OF_NAME_ARRAY);
}
Note I added a name_size field. C does not store the size of allocated arrays, so you might need this for safe copy/compare, etc. (prevent buffer overflows).
Using *one makes this term independent of the actual type used. The size of such a struct is as if the arrray had zero elements. However, it will be properly aligned, so it can differ from the same struct without the array.
Also note that you have to change the allocated size if you use other than a char array to something like sizeof(element_type) * ARRAY_SIZE. This is not necessary for chars, as their size is defined by the standard to be 1.
my guess: a flexible struct would be one that could handle any age and any name.
A unsigned int field would handle any age (within reason).
A char * field would handle any name.
The struct itself would be:
struct nameAge { unsigned int age; char * pName; };
an instance of the struct would be:
struct nameAge myNameAge;
Setting the age field would be:
myNameAge.age = ageValue;
Setting the name field would be:
myNameAge.name = malloc( numCharactersInName+1 );
strcpy( myNameAge.name, nameString );
How the code obtained the ageValue for age and/or the characters for NameString is up to the programmer to decide/implement.

passing array of variables to function in C

I have a C function which needs a large amount of variables to be passed, so I came to the idea of "packing" them all in a single array (matrix of variables). The point is, these variables are of a very different type, some int, some arrays (strings and vectors), and many of them float. Is there a way to leave unspecified the type of data stored into the matrix? (I unsuccessfully explored the void "data type")
The elements of an array are always of a single type, that's the point.
Collecting variables of multiple types is the job for a structure, i.e. a struct.
This is a quite common way to solve this particular problem. If the structure becomes large, you might find it convenient to pass a pointer to an instance of it, rather than copying the entire thing in the call.
You can use va_list but struct is the best way to do it
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
enum type {
INT,
FLOAT,
PCHAR,
};
struct any_type {
enum type type_;
union {
int int_;
float float_;
char* pchar_;
};
};
#define MYSIZE 10
void process(size_t size, struct any_type* array)
{
for(int i = 0; i < size; i++) {
switch(array[i].type_) {
case INT :
printf("INT: %d\n", array[i].int_);
break;
case FLOAT :
printf("FLOAT: %f\n", array[i].float_);
break;
case PCHAR :
printf("PCHAR: %s\n", array[i].pchar_);
break;
default:
printf("UNKNOWN TYPE PROVIDED\n");
break;
}
}
}
int main(int argc, char *argv[])
{
struct any_type *array;
array = malloc(MYSIZE*(sizeof(struct any_type)));
array[0].type_ = INT;
array[0].int_ = 10;
array[1].type_ = FLOAT;
array[1].float_ = 2.5;
array[2].type_ = PCHAR;
array[2].pchar_ = "hello char";
process(3, array);
return 0;
}
You can extend type and union as needed. However using nameless unions require -std=c11.
Expanding on my comment above:
Needing to pass a large number of parameters1 to a function can be a sign that there is a problem in your design - your function may be trying to do too many things at once, and you would be better off refactoring it into several smaller functions, each of which only takes a subset of the parameters.
Assuming that's not the case, how are your parameters logically related to each other? Can they be considered attributes of a single data item? For example, a person may be described by the following attributes: surname, given name, birth date, sex. These can be collected together into a single struct type such as
#include <time.h>
struct person {
char *surname;
char *name;
struct tm birthdate; // struct tm defined in time.h
char sex;
};
void write_to( struct person *p )
{
p->surname = strdup( "McGillicuddy" );
p->name = strdup( "Aloysius" );
p->sex = 'M';
p->birthdate.tm_year = 32; // tm_year starts at 1900, so this is 1932
p->birthdate.tm_mon = 11; // december
p->birthdate.tm_day = 1;
};
int main( void )
{
struct person p;
...
write_to( &p );
...
}
Note that members of struct types can themselves be struct types - struct tm is a type defined in time.h that specifies a datetime value using multiple attributes.
Some notes on syntax:
When you want to access a member of a struct instance, use the . operator. When you want to access a member of a struct through a pointer, use the -> operator. In the function write_to, p is a pointer to struct person, so to access each member of p we use ->. The birthdate member is an instance of struct tm, not a pointer, so we use the . operator to access each member of birthdate.
p->m is equivalent to (*p).m.
Like I said in my comment, you should not collect otherwise unrelated items into a struct type just to reduce the number of parameters being passed to a function. They should all be attributes of a more complex type. Some other examples of what I mean:
// A node in a list
struct node {
data_t data; // for some data type data_t;
struct node *next;
struct node *prev;
};
// A street address
struct addr {
char *number; // to handle things like 102A, 102B
char *street;
char *city;
char state[3];
char *zip;
};
It's possible that you're really passing only a couple of distinct data items to your function, each of which is composed of a lot of different attributes. Take a step back and look at your variables and see how they relate to each other.
"Large" depends on context, and of course there are always exceptions to any rule, but in general passing more than 7 distinct, unrelated parameters is a sign you may need to refactor your function into several smaller functions.

Defining elastic/flexible structure in C

I have a task to do and the content of the task is:
Please suggest a definition of linked list, which will keep the person's name and age in a flexible structure. Then write the procedure for inserting elements with the given name and age.
What exactly is a flexible structure? How to define it? And then how to malloc the size?
typedef struct Test {
int age; // ?
char name[?]; // ?
struct Test * next;
}Structure;
int main(void) {
Structure *one = malloc(???);
}
You are on the right track. However, there is no "flexible structure". You want to use a flexible array member (avail since C99) in a struct:
typedef struct {
int age;
size_t name_size; // size of the array, not length of the name!
char name[]; // Flexible array member
} Structure;
int main(void) {
Structure *one = malloc(sizeof(*one) + SIZE_OF_NAME_ARRAY);
}
Note I added a name_size field. C does not store the size of allocated arrays, so you might need this for safe copy/compare, etc. (prevent buffer overflows).
Using *one makes this term independent of the actual type used. The size of such a struct is as if the arrray had zero elements. However, it will be properly aligned, so it can differ from the same struct without the array.
Also note that you have to change the allocated size if you use other than a char array to something like sizeof(element_type) * ARRAY_SIZE. This is not necessary for chars, as their size is defined by the standard to be 1.
my guess: a flexible struct would be one that could handle any age and any name.
A unsigned int field would handle any age (within reason).
A char * field would handle any name.
The struct itself would be:
struct nameAge { unsigned int age; char * pName; };
an instance of the struct would be:
struct nameAge myNameAge;
Setting the age field would be:
myNameAge.age = ageValue;
Setting the name field would be:
myNameAge.name = malloc( numCharactersInName+1 );
strcpy( myNameAge.name, nameString );
How the code obtained the ageValue for age and/or the characters for NameString is up to the programmer to decide/implement.

storage size of ‘s’ isn’t known + pointer to pointer

Greeting,
I faced the error of "Assignment_1.c:10:18: error: storage size of ‘s’ isn’t known" I am not expert in using pointer to pointer, I want to have a dynamic sized array of dynamic sized words. Any idea?
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int size = MAX;
typedef struct{
int numberOfWords,averageWordLength,id;
char ** words;
}sentence;
void main(){
struct sentence s;
s.numberOfWords=3;
s.averageWordLength=5;
s.id=1;
s->words= malloc(size * sizeof(s));
//printf("%s",s.words);
}
Do not use typedef for structs unless you are trying to create an opaque type. This is wrong. struct is a great hint to C developers. Linus had a good description of this:
It's a mistake to use typedef for structures and pointers. When you
see a
vps_t a;
in the source, what does it mean?
In contrast, if it says
struct virtual_container *a;
you can actually tell what "a" is.
Lots of people think that typedefs "help readability". Not so. They
are useful only for:
(a) totally opaque objects (where the typedef is actively used to
hide
what the object is).
Example: "pte_t" etc. opaque objects that you can only access using
the proper accessor functions.
NOTE! Opaqueness and "accessor functions" are not good in themselves.
The reason we have them for things like pte_t etc. is that there
really is absolutely _zero_ portably accessible information there.
(b) Clear integer types, where the abstraction helps avoid
confusion
whether it is "int" or "long".
u8/u16/u32 are perfectly fine typedefs, although they fit into
category (d) better than here.
NOTE! Again - there needs to be a _reason_ for this. If something is
"unsigned long", then there's no reason to do
typedef unsigned long myflags_t;
but if there is a clear reason for why it under certain circumstances
might be an "unsigned int" and under other configurations might be
"unsigned long", then by all means go ahead and use a typedef.
(c) when you use sparse to literally create a new type for
type-checking.
...
Do not declare a bunch of variables in a row. You only confuse others by doing that.
And of course you cannot refer to a member field using . operator, you have to use ->. That being said, you code should look something like:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct sentence {
int numberOfWords;
int averageWordLength;
int id;
char **words;
};
int main()
{
struct sentence s;
s.numberOfWords = 3;
s.averageWordLength = 5;
s.id = 1;
s.words = malloc(MAX * sizeof(s));
/* printf("%s",s.words); */
return EXIT_SUCCESS;
}
Also consider having `words as the first member of the structure or you waste memory due to misalignment on platforms where alignment of a pointer is greater than integer.
Use '->' when the structure's object is a pointer type. This should work:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int size = MAX;
typedef struct{
int numberOfWords,averageWordLength,id;
char *words;
}sentence;
void main(){
sentence s;
s.numberOfWords=3;
s.averageWordLength=5;
s.id=1;
s.words= malloc(size * sizeof(s));
//printf("%s",s.words);
}
In
typedef struct {
int numberOfWords, averageWordLength, id;
char **words;
} sentence;
you create a unnamed struct and an alias for that struct. The alias name is sentence.
You now have a new type in your code. The new type name is sentence. If you provided a tag there would be 2 new type names: sentence and struct tag.
typedef struct tag {
whatever;
} sentence;
Also note the typedef isn't really needed
struct tag {
whatever;
};
The snippet above defines a new type named struct tag.

Resources