How can a function create a struct? - c

One of my assignments for the C Programming course was define a function called create_card. This function receives a suit character and an a card value, and returns a card_t struct.
Question: How is a function supposed to create a struct? Can't it only create values for the struct? Did I misinterpret the meaning of the question or was the assignment written down wrong?

This is an example of a function returning a struct.
struct test {
int a;
};
struct test Fun(int k) {
struct test d;
d.a=k;
return d;
}
Replace struct test with the name of your struct and the definition of struct test with your struct's definition.
How to use
int main() {
struct test Test=Fun(6);
printf("%d",Test.a); // prints '6'
return 0;
}

You can either return a struct from a function like in ForceBru's answer, or you can create a struct in C dynamic memory (a.k.a. the heap), using malloc, and return a pointer to it, e.g.
struct foo_st {
int num;
const char* str;
};
struct foo_st*
/* the second argument s should practically be a literal string */
make_foo (int n, const char* s) {
struct foo_st* p = malloc(sizeof(struct foo_st));
if (!p) { perror("malloc foo"); exit(EXIT_FAILURE); };
p->num = n;
p->str = s;
return p;
}
Your main (or some other function) might later do struct foo_st*fooptr = make_foo(32, "abc"); but someone should call free(fooptr) (or at least, free the address which has been inside fooptr).
Of course, you should never forget to free a malloc-ed pointer when it becomes useless. Be afraid of memory leaks, buffer overflow and undefined behavior. Read more about malloc(3) & free.
BTW, in practice you should decide of who is responsible for free-ing memory. In the above make_foo example, the second parameter to make_foo is supposed to be a literal string (if it is malloc-ed e.g. using strdup(3), you'll need to free it elsewhere, and that becomes very messy).
In practice you should document the conventions about who is responsible to free some dynamically previously mallocated memory. You might want to use valgrind (if your system has it), and, if using a recent GCC compiler, its -fsanitize=address option to hunt memory related bugs. Very often, you happen to code both making and destroying functions (like here or here).
You might want to read about garbage collection (at least, to understand the concepts, such as reference counting, and the terminology). Perhaps you'll later want to use Boehm's conservative garbage collector.

Related

Allocate space for struct pointer member through constructor

I want to use structs like objects in C.
Suppose I have the following:
typedef struct {
/* ... */
size_t *pages_len;
} book;
And I use the following method to construct it:
int book_init(/* some args... */, book * b) {
/* do some validation */
/* compute the number of pages n_pages */
b->pages_len = (size_t*) calloc(n_pages, sizeof(size_t));
/* compute pages_len based on some args */
return 0;
}
Then I construct an object like this:
book *my_book = (book*)malloc(sizeof(my_book));
if (book_init(/* some args */, my_book) == 0) {
/* do something */
}
And I destroy my object like: book_destroy(book *b) where I free(b->pages_len).
Is this correct or am I missing something? I can't show the original code but I am having trouble:
Accessing b->pages_len after the init method.
Destroying the object. I am having memory corruption.
As requested, a minimal reproducible example:
/* book.h */
#ifndef BOOK_HEADER_
#define BOOK_HEADER_
#include <ctype.h>
typedef struct
{
size_t pages_count;
size_t *pages_len;
} * book;
int book_create (book b);
#endif /* BOOK_HEADER_ */
/* book.c */
#include "book"
int
book_create (book b)
{
b->pages_len = calloc (3, sizeof (b->pages_len));
b->pages_len[2] = 20;
return 0;
}
/* test.c */
#include "book.h"
int main(int argc, char** argv) {
book my_book = (book)malloc (sizeof (book));
int r = book_create (my_book);
printf ("\n%lu\n", my_book->pages_len[2]);
free (my_book->pages_len);
free (my_book);
}
What I get from my memory leak detector is that free(my_book) gives a Memory corruption (written out of bounds?) error. One thing that fixed this error was changing the order of pages_count and pages_len but I don't know why.
I just typed the above example, so if there is any typo or syntactic error, please let me know. Thank you.
book my_book = malloc(sizeof(book)) is wrong. Note that the type of book is pointer to your struct, but you want to allocate enough space for the struct itself. So as the code stands, you will need to write malloc(sizeof(*my_book)).
However, using typedef to define a name for a pointer is usually bad style; it leads to confusion, and you will find it very awkward that your struct type doesn't have a name. A better way to write this would just be as
struct book
{
size_t pages_count;
size_t *pages_len;
};
struct book *my_book = malloc(sizeof(*my_book));
In this case malloc(sizeof(struct book)) would also work, but will become broken if you ever change the type of my_book.
It's often suggested that you not typedef away the struct, and just keep calling it struct book everywhere, because it's usually good to remember what kind of object you are working with. But if you must, you can still do typedef struct book book; afterwards. As mentioned, I would not recommend typedef struct book *book;.
Casting the result of malloc should never be necessary in C. You presumably included it because you got a warning about the return type of malloc, but the correct fix is to include the standard header <stdlib.h>. Indeed, this is precisely the reason why people usually recommend that you do not cast the result of malloc, because it can silence warnings that indicate a real bug. See Do I cast the result of malloc? for much more on this topic.
You also need <stdio.h> in test.c.
Also, create_book should return a value (but this is not the cause of your crash, since you never use it).
It is not surprising that rearranging the struct members made the bug appear to go away. What probably happened is something like this. On a typical 64-bit system, size_t and pointers are each 8 bytes. So you had allocated 8 bytes for your struct, when its size is actually 16. But you only actually wrote to the pages_len member. So if pages_len is the first member of the struct, and you never write to the pages_count member, you are only writing within the 8 bytes you allocated, and nothing goes wrong. Of course, the code was still broken, and as soon as you added any code that used the pages_count member, or added or rearranged any members of your struct, the bug would be back.
But in general, blindly changing things until a bug goes away is an extremely bad idea when programming in C. You may very easily do something that only masks the bug and makes it harder to find. There's no substitute for actually understanding what is happening.

Struct by value in loop

Say I have a function from another api that returns structs by value
struct foo{
int bar;
bool success;
}
foo getThefoo();
What happens in a loop if this function is called eg
int foolen = 0;
foo** foos;
do {
foolen++;
foos = realloc(foos,sizeof(foo*)*foolen);
foo myfoo = getThefoo();
foos[foolen-1]=&myfoo;
}while (/**something*//)
Does a new foo struct get allocated on the stack for each iteration?. Or is the initial allocation reused?. I ask because taking a pointer to that structure might be an unexpected value.
getThefoo is defined in an external library. So its not trivial to make that return a pointer to a food structure.
This won't work, you're storing the address of a local which will go out of scope, rendering the stored addresses useless.
The proper fix seems to be to not store pointers to struct foos in the array, but just storing them directly:
struct foo *foos = NULL;
size_t foolen = 0;
do {
++foolen;
foos = realloc(foos, foolen * sizeof *foos);
foos[foolen - 1] = getTheFoo();
} while(something something);
Of course, the usual caveats apply:
It's more efficent to call realloc() less often, by over-allocating and tracking array length and array allocated space separately.
realloc() can fail, the above loses the old allocation (if any) when that happens.
Note that structures are values and thus fully assignable, so that's what we do.

Creating an Instance of a struct

I have this struct
struct FluxCapacitor{
unsigned char* c_string;
unsigned int value;
};
Now I need to create an instance of this struct. I googled this problem and found that I have to use something like this
typedef struct FluxCapacitor{
unsigned char* c_string
unsigned int value;
};
But I dont really understand the next step with malloc(). Can someone explain it to me?
You do not need malloc() to create an instance of a struct. And I would recommend that you avoid typedefing structures merely to reduce keystrokes. The extra keystrokes would only be saved in declarations and function prototypes (and maybe if you need to cast something), since you don't need the struct keyword elsewhere; the advantage is that when you see struct FluxCapacitor, you know exactly what it is. If you only see FluxCapacitor alone, you don't know if it is a typedef for a struct, or a union, or an integer type or what.
Note that the posted code was missing the semicolon at the end of the declaration. Also, it is unclear why you have unsigned char* c_string;. This may not allow assignment to a string literal. I have changed this in the code below. You can create a single struct like this:
struct FluxCapacitor
{
char *c_string;
unsigned int value;
};
...
struct FluxCapacitor fcap_1;
You can then assign values to the fields of fcap_1:
fcap_1.c_string = "McFly";
fcap_1.value = 42;
Note that you could also use designated initializers at the point of declaration:
struct FluxCapacitor fcap_2 = { .c_string = "Biff",
.value = 1985
};
If you need an array of FluxCapacitor structures, just declare one:
struct FluxCapacitor fcaps[2];
You can assign to the fields of each array member in a loop:
struct FluxCapacitor fcaps[2];
char *somestrings[] = { "McFly", "Biff" };
unsigned somevalues[] = { 42, 1985 };
for (size_t i = 0; i < 2; i++) {
fcaps[i].c_string = somestrings[i];
fcaps[i].value = somevalues[i];
}
Alternatively, you can use designated initializers here too:
struct FluxCapacitor fcaps[2] = { { .c_string = "McFly", .value = 42 },
{ .c_string = "Biff", .value = 1985}
};
Using malloc()
Since OP seems determined to use malloc(), it would be good to first recall that memory allocated with malloc() must later be deallocated with free(). Also note that malloc() can fail to allocate memory, returning a null pointer. Thus the result of a call to malloc() must be checked before attempting to dereference this pointer. The additional complexity should be avoided in favor of the above approaches unless OP has good reason to do manual allocation.
In the code below, the function create_flux_cap() takes a string and an unsigned int as arguments, and returns a pointer to a newly allocated FluxCapacitor structure with the arguments assigned to the appropriate fields. Note that since the FluxCapacitor structure is accessed through a pointer, the arrow operator is used instead of the dot operator.
Inside the function, the return value from the call to malloc() is checked before attempting assignment. If the allocation has failed, no assignment is made and a null pointer is returned to the calling function. Note that in the call to malloc(), the result is not cast, since there is no need for this in C and it needlessly clutters the code. Also observe that an identifier is used instead of an explicit type with the sizeof operator. This is less error-prone, easier to maintain if types change in the future, and is much cleaner code. That is, instead of this:
new_fcap = (struct FluxCapacitor *)malloc(sizeof (struct FluxCapacitor));
use this:
new_fcap = malloc(sizeof *new_fcap);
In main(), the return values from the calls to create_flux_cap() are checked. If an allocation has failed, the program exits with an error message.
The stdlib.h header file has been included for the function prototypes of malloc() and exit(), and also for the macro EXIT_FAILURE.
#include <stdio.h>
#include <stdlib.h>
struct FluxCapacitor
{
char* c_string;
unsigned value;
};
struct FluxCapacitor * create_flux_cap(char *, unsigned);
int main(void)
{
struct FluxCapacitor *fcap_1 = create_flux_cap("McFly", 42);
struct FluxCapacitor *fcap_2 = create_flux_cap("Biff", 1985);
/* Check for allocation errors */
if (fcap_1 == NULL || fcap_2 == NULL) {
fprintf(stderr, "Unable to create FluxCapacitor\n");
exit(EXIT_FAILURE);
}
/* Display contents of structures */
printf("%s, %u\n", fcap_1->c_string, fcap_1->value);
printf("%s, %u\n", fcap_2->c_string, fcap_2->value);
/* Free allocated memory */
free(fcap_1);
free(fcap_2);
return 0;
}
struct FluxCapacitor * create_flux_cap(char *str, unsigned val)
{
struct FluxCapacitor *new_fcap;
new_fcap = malloc(sizeof *new_fcap);
if (new_fcap != NULL) {
new_fcap->c_string = str;
new_fcap->value = val;
}
return new_fcap;
}
You need malloc for dynamic allocation of memory.In your case, both the types char and int are known to the compiler, it means the compiler can know the exact memory requirement at compile time.
For e.g. you can create a struct object like in the main function
#include<stdio.h>
#include<stdlib.h>
struct FluxCapacitor{
unsigned char* c_string;
unsigned int value;
};
int main() {
FluxCapacitor x;
x.c_string = "This is x capacitor"
x.value = 10
}
The x is of value type. You can make a copy and pass around this value. Also, observe we are using . notation to access its member variables.
But this doesn't happen at all time. We are not aware of future FluxCapacitor requirement and so above program will need more memory as while it is running and by using the malloc we can ask the compiler to provide us requested memory. This is a good place to use malloc, what malloc does is, it returns us a pointer to a piece of memory of the requested size. It is dynamic memory allocation.
Here's a simple example: let suppose if you need struct declaration of FluxCapacitor but don't know how many you will need, then use malloc
#include<stdio.h>
#include<stdlib.h>
typedef struct FluxCapacitor {
unsigned char* c_string;
int value;;
} flux;
// typedef is used to have the alias for the struct FluxCapacitor as flux
int main() {
flux *a = malloc(sizeof(flux)); // piece of memory requested
a -> c_string = "Hello World"; // Pointer notation
a -> value = 5;
free(a); // you need to handle freeing of memory
return 0;
}
.

A Simple Object System

I'm working my way through the learn c the hard way book and have run into a few issues on Exercise 19. The author said that ex19 was intended for the learners to get to know the macro in c. I have no problem in understanding the concept of that, but I just don't understand everything else. I can't understand how the object prototype is created.
Especilly,what does the following sentense mean?
Since C puts the Room.proto field first, that means the el pointer is
really only pointing at enough of the block of memory to see a full
Object struct. It has no idea that it's even called proto.
the relevant code is this:
// this seems weird, but we can make a struct of one size,
// then point a different pointer at it to "cast" it
Object *el = calloc(1, size);
*el = proto;
can anyone tell me how on earth malloc/calloc exactly works? As far as i know, it just allocate the required number of memory and return the first address. If so, how can the computer know the data struct of the allocated memory? like in the code, after Room *arena = NEW(Room, "The arena, with the minotaur");,you can do this directly arena->bad_guy = NEW(Monster, "The evil minotaur"); how does the computer know there is a bad_guy??
what on earth is the content of *el after the above two statements(Object *el = calloc(1, size); and *el = proto;)?
Any help will be appreciated!!
the link to the exercise: http://c.learncodethehardway.org/book/ex19.html
calloc has the additional feature that it fills the allocated memory with zero bytes, whereas using the equivalent malloc call would require an additional step if all or some of the allocation needs to be zero initially.
In the code
arena->bad_guy = NEW(Monster, "The evil minotaur");
the compiler knows the layout of the struct because the access is through the arena variable, which is declared as a pointer to Room, which is presumably a typedef of a struct.
For the other part, the guarantee of ordering within structs allows a limited form of inheritance in composite structs, or extended structs.
struct A {
int x;
};
struct B {
int foo;
double baloney;
};
struct B (or a pointer to it) can be cast to a (pointer to a) struct A because they both begin with an int. Of course, if you cast the other way, the struct A must have been originally a struct B or access to the baloney field will be undefined. In other words, struct B essentially begins with a struct A.
This may be easier to see if I rewrite my example like this:
struct A {
int x;
};
struct B {
struct A foo;
double baloney;
};
Now you can get a struct A out of struct B in different ways.
struct A a;
struct B b;
a = b.foo; // regular member variable access
struct A *ap = &a;
struct B *bp = &b;
ap = (struct A *)bp; // cast the pointer
ap = & b.foo; // take a pointer from the member variable
ap = & bp->foo; // take a pointer from the member variable via a pointer
All it does is to alloc 1*size bytes. There's nothing magic with malloc/calloc. He is passing the sizeof(T) to the function through that NEW macro and putting it in Object_new's size parameter. So all the function knows is the size in bytes.

Mallocing an Array in C

I have the following piece of code which I would expect to fail but seems to be working correctly. I'm confused by why this is not causing some sort of segmentation fault.
#include <stdio.h>
#include <stdlib.h>
struct entry {
int foo;
};
struct table {
int size;
struct entry* entries;
};
typedef struct table *Table;
typedef struct entry Entry;
int main() {
Table table = malloc(sizeof(struct table));
table->entries = malloc(sizeof(struct entry) * 1);
(table->entries)[5].foo = 5;
for (int i = 0; i < 10; i++) {
printf("Entry #%d: %d\n",i,(table->entries)[i].foo);
}
}
I would have expected that since I only malloced enough space for one entry in table->entries, accessing any index other than 0 would be out of bounds. But when I run this program it prints out 5 for as the foo value of the entry at index 5, and the rest as 0, which is the correct behavior. Why is this not failing?
Someone else will say it better, but Undefined Behavior is undefined.
It's not defined. It might work. It might not.
It all depends what is in those memory locations.
You wrote one bad location. You read some others. You happened to not hit anything
too important.
You wrote one word well past your malloc'ed area. Perhaps if you did more computations
that would cause trouble because you wrote into malloc's data structures. Maybe not.
You are accessing out of bounds, but that merely invokes 'undefined behaviour'. Anything may happen when you invoke 'undefined behaviour'. One possibility is that the program crashes; another is that the program does not crash and appears to be OK. Either is possible; it is even possible for it sometimes to crash and sometimes not crash.
If you tried more memory allocation, or tried freeing memory, you'd be more likely to see that things have gone wrong. However, even that's not guaranteed; you may have missed all the sensitive information (the bytes that are used by malloc() et al to determine which memory is allocated and which is not).
You can write:
table->entries[i].foo
You don't need the parentheses around (table->entries)[i].foo, though they're harmless except that they suggest a neophyte was coding.
Its not failing because despite you are writing to unallocated memory, this memory is perfectly inside the legal HEAP space. But sinse you didn't declare to the memory manager that you are using that memory space, a future malloc() may try to alloc to the same area, and you will get overlapping buffers and undefined behaviour.
This is undefined behavior that you are accessing memory location which is not 'yours'. You have writern some thing in memory which is not allocated by you, corrupting that memory location.
#include <stdio.h>
#include <stdlib.h>
struct entry {
int foo;
};
struct table {
int size;
struct entry* entries;
};
typedef struct table *Table;
typedef struct entry Entry;
int main() {
Table table =(table)malloc(sizeof(struct table));
table->entries =(entry*)malloc(sizeof(struct entry) * 10);
(table->entries)[5].foo = 5;
for (int i = 0; i < 10; i++) {
printf("Entry #%d: %d\n",i,(table->entries)[i].foo);
}
}
First, you need to convert the (void*) type into the pointer type you want when using malloc. Second, you only allocate entries pointers, which means, when you use (table->entries)[5].foo, you might access memory illegal, so it's a dangerous behavior. Finally, you need to initialize foo before you print it. You need to obey the rules, do not write codes like that.

Resources