Double linked list2 - c

I did a lot of linked lists already,
but I didn't use them for a while and didn't really programm anything, therefore I am litterally lost.
The following is my Code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int pers_num;
char name[100];
void *previous;
void *next;
}Person;
int main(){
Person first_element;
Person last_element;
first_element.next = (Person *)(&last_element);
last_element.age = 19;
printf("%d\n",(&last_element)->age);
printf("%d\n",(first_element.next)->age);
}
Could you explain to me why following error is thrown?
speicher.c: In function 'main':
speicher.c:22:39: warning: dereferencing 'void *' pointer
23 | printf("%d\n",(first_element.next)->age);
| ^~
speicher.c:23:39: error: request for member 'age' in something not a structure or union
As I understand it "first_element.next" should be the pointer which points at last_element.
therefore you should be able to use the -> to access the data inside last_element.
The line 22 Runs perfectly even thought it should have the same Output as line 23, where the error is thrown.

You can't dereference a void pointer because it's a pointer that references a void type :-) In other words, it doesn't really know what actual type it points at. The reason why the two lines behave differently are, keeping in mind that a->b is just syntactic sugar for (*a).b:
printf("%d\n",(&last)->age);
// This (&last)->age, which is actually the same
// as last.age. In both cases, the type being used
// to get the age field is Person, so no problem.
printf("%d\n",(first.next)->age);
// This (first.next)->age is the same as
// (*(first.next)).age. Because first.next is of type
// void *, it cannot be dereferenced.
What you are doing is akin to declaring a variable with void x, which is not valid (don't confuse that with void *x which is valid).
You would be better off (within the structure) pointing to the actual type you want, with something like:
typedef struct s_Person { // A
int age;
int pers_num;
char name[100];
struct s_Person *previous, *next;
} Person; // B
Note that you cannot use the Person type definition while you're creating it, since it does not yet exist. Simplistically, you can think of it coming into existence at the B point. The named structure s_Person comes into existence at A so it can be used within the structure.

Related

C: Putting a function pointer in a structure where the function uses that structure as an argument

I seem to have run into a chicken and egg problem.
I want to have a structure that as one of its members is a function pointer. However this function pointer wants to use that same structure as it's argument. This creates an issue where I have to define the function pointer before I can include it as a member, but I can't properly define it until I've defined the structure.
I have found that if I simply leave the argument list for the function pointer blank it SEEMS to work, though what I have read is that this is potentially fraught with issues.
Below is what I currently have:
#include <stdio.h>
typedef void (*IO_fun_ptr_t)();
typedef struct IO_config_t{
int address;
IO_fun_ptr_t IO_fun_ptr; //pointer to the function to be used
} IO_config_t;
void print_address (IO_config_t *input){
printf("The address is %d \n", input->address);
printf("Push any key to continue:");
getchar();
}
void main()
{
IO_config_t input = {.address = 16,
.IO_fun_ptr = &print_address};
input.IO_fun_ptr(&input);
}
The result is:
The address is 16
Push any key to continue:
This works but I'm concerned about the potential implications of leaving that argument blank.
As a bit of an aside, I originally thought that I should be able to use void* as an argument as a placeholder for pointer to an unknown argument type, but I would get compile errors when doing so at the point where I assign the pointer to my function:
typedef void (*IO_fun_ptr_t)(void *);
(Error[Pe144]: a value of type "void (*)(IO_config_t *)" cannot be
used to initialize an entity of type "IO_fun_ptr_t")
Any advice on how to do this better and cleaner?
Use forward-declarations.
This is a way of stating that a structure exists, but without providing details of all the members of the structure until later.
#include <stdio.h>
// 1.) Forward declaration: Here is the name of the structure
// but member-details are omitted.
struct IO_config_t;
// 2.) typedef of the structure
// Still no details on the members.
typedef struct IO_config_t IO_config_t;
// 3.) The parameter to the function is listed, using the definition
// from step 2.) (note: Still no details on the members yet)
typedef void (*IO_fun_ptr_t)(IO_config_t* input);
// 4.) Now we actually detail the members of the structure
struct IO_config_t{
int address;
IO_fun_ptr_t IO_fun_ptr;
};
void print_address (IO_config_t *input){
printf("The address is %d \n", input->address);
printf("Push any key to continue:");
getchar();
}
void main()
{
IO_config_t input = {.address = 16,
.IO_fun_ptr = &print_address};
input.IO_fun_ptr(&input);
}
This is demonstrated in the short program: https://ideone.com/p3jBYt
So I had searched through stack exchange and couldn't find anything so humbled myself to asking a question. Just as I'm getting to the end of writing everything up, I glance over to the "Similar Questions" box to the right, and I happen to see the following question that I didn't come across before:
How to properly define a function pointer in struct, which takes struct as a pointer?
And in its answer I found my answer. I simply have to define the function pointer in the structure itself, not before hand. (I had tried, but forgot to include the struct keyword in the definition so it didn't work since the type def wasn't complete I am guessing).
Below is what compiles clean and seems to work:
#include <stdio.h>
typedef struct IO_config_t{
int address;
void (*IO_fun_ptr)(struct IO_config_t *); //pointer to the function to be used
} IO_config_t;
void print_address (IO_config_t *input){
printf("The address is %d \n", input->address);
printf("Push any key to continue:");
getchar();
}
void main()
{
IO_config_t input = {.address = 16,
.IO_fun_ptr = &print_address};
input.IO_fun_ptr(&input);
}

How to make cross pointers in structs

So here's my problem, I want to create a graph-database. My concept idea is a node (which will be of type "Vrtc" in the code. It will cointain an (int) id, a (char*) string (called "str") and a list (l_est) of paths in and out.
The list will contain an "array" of pointers to nodes, the amount of nodes in the list, and the maximum number of nodes.
typedef struct Vrtc
{
int id;
char *str;
l_est *pathsIn;
l_est *pathsOut;
} Vrtc;
typedef struct l_est{
Vrtc **Vert;
int qtdElem;
int maxElem;
} l_est;
As you may know, there'll be a problem of "Unknow type/Type undeclared inside the node. I was hoping anyone could give a tip of how to do it, if it is possible.
You have to use a forward declaration:
typedef struct l_est l_est;
typedef struct {
int id;
char *str;
l_est *pathsIn, *pathsOut;
} Vrtc;
typedef struct l_est {
Vrtc **Vert;
int qtdElem, maxElem;
} l_est;
The first type definition of struct l_est is a so-called "incomplete type". This type may not be used for variables or with sizeof but it may be used to declare pointer.
The incomplete type may later be overridden by a "complete type" without complaints of the compiler.
Similar solutions can be found in other languages (e.g. Pascal).

copying the content of an dynamic array of structs into another dynamic array using memcpy

I want to copy the content of a dynamic array containing 2 structs to another dynamic array of the same size.
I need an exact copy. When I compile, I get these 2 errors at the last line:
invalid use of undefined type ‘struct student’ & dereferencing pointer to incomplete type
I don't understand these 2 errors.
Here is my code:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct Movie{
char name [7];
int price;
int year;
};
int main(int argc, char ** argv){
struct Movie m1,m2;
strcpy(m1.name,"Rambo");
m1.price=20;
m1.year=1980;
strcpy(m2.name,"universal soldier");
m2.price=30;
m2.year=1990;
struct Movie * db= malloc(2*sizeof(struct Movie));
*db=m1;
*(db+1)=m2;
int i;
for(i=0;i<2;i++){
printf("%s\n",(*(db+i)).name);
}
struct student * db_copy= malloc(2*sizeof(struct Movie));
memcpy(&db_copy,&db,sizeof(db));
for(i=0;i<2;i++){
printf("%s\n",(*(db_copy+i)).name); //here occur the two errors
}
}
You need to let the compiler know what struct student is, and that's nowhere in the code.
The errors mean:
invalid use of undefined type ‘struct student’: You're using an undefined type
dereferencing pointer to incomplete type: You're dereferencing (accessing actual value / structure) of an incomplete type, since the definition of the type is missing.
I guess the real problem though is that you meant to write:
struct Movie * db_copy= malloc(2*sizeof(struct Movie));

Why does "struct T* next" compile when T isn't an existing type?

I am using MinGW on Windows. I am building linked list and I am confused with this.
#include <stdio.h>
#include <stdlib.h>
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
int main(void)
{
List item;
List * head;
head = NULL;
return 0;
}
I now that struct can't have struct variable(object, instance of that struct), but can have pointer of that struct type. Didn't know that pointer can be pointer of unexisting type. struct BlaBla * next;(not for linked list, it must be struct Data * next but mean general talking)
Yes, you can, because then the compiler, upon encountering the unknown type name for the first time, assumes that there's somehwere a struct type definition with this name. Then it will forward-declare the struct name for you, let you use it as a pointer, but you can't dereference it nor can you do pointer arithmetic on it (since it's an incomplete type).
The compiler will accept code such as your example:
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
This is okay because the size of pointers is known to the compiler, and the compiler is assuming that the struct will be defined before it is dereferenced.
Because the compiler acts this way, it's possible to do this:
typedef struct Data
{
int x;
int y;
struct Data * next; /* points to itself */
} List;
However, if you were to include the struct inline, like this:
typedef struct Data
{
int x;
int y;
struct BlaBla blaStruct; /* Not a pointer. Won't compile. */
}List;
The compiler can't work out how big struct Data is because it doesn't know how big struct BlaBla is. To get this to compile, you need to include the definition of struct BlaBla.
Note that, as soon as you need to access the members of struct BlaBla, you will need to include the header file that defines it.
It depends on what you mean by "unexisting". If you haven't even declared BlaBla, you'll get an error.
If you've declared it but not yet defined it, that will work fine. You're allowed to have pointers to incomplete types.
In fact, that's the normal way of doing opaque pointers in C.
So, you might think that this is invalid because there's no declaration of struct BlaBla in scope:
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
However, it's actually okay since it's both declaring struct BlaBla and defining next at the same time.
Of course, since definition implies declaration, this is also okay:
struct BlaBla { int xyzzy; };
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
In order to declare a variable or field of a given type, pass one as a parameter, or copy one to another of the same type, the compiler has to know how many bytes the variable or field occupies, what alignment requirements it has (if any), and what other pointer types it's compatible with, but that's all the compiler needs to know about it. In all common dialects of C, a pointer to any structure will always be the same size and require the same alignment, regardless of the size of the structure to which it points or what that structure may contain, and pointers to any structure type are only compatible with other pointers to the same structure type.
Consequently, code which doesn't need to do anything with pointers to a structure except allocate space to hold the pointers themselves [as opposed to the structures at which they point], pass them as parameters, or copy them to other pointers, doesn't need to know anything about the structure type to which they point beyond its unique name. Code which needs to allocate space for a structure (as opposed to a pointer to one) or access any of its members must know more about its type, but code which doesn't do those things doesn't need such information.

What does the code below mean, in regards to structs in C?

I'm really new to C programming and I'm still trying to understand the concept of using pointers and using typedef structs.
I have this code snippet below that I need to use in a program:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
I'm not exactly sure what this does - to me it seems similar as using interfaces in Objective-C, but I don't think that's the case.
And then I have this line
pStudentRecord* g_ppRecords;
I basically need to add several pStudentRecord to g_ppRecords based on a number. I understand how to create and allocate memory for an object of type pStudentRecord, but I'm not sure how to actually add multiple objects to g_ppRecords.
defines a pointer to the struct described within the curly bracers, here is a simpler example
typedef struct {
int x;
int y;
}Point,* pPoint;
int main(void) {
Point point = {4,5};
pPoint point_ptr = &point;
printf("%d - %d\n",point.x,point_ptr->x);
pPoint second_point_ptr = malloc(sizeof(Point));
second_point_ptr->x = 5;
free(second_point_ptr);
}
The first declares an unnamed struct, and a type pStudentRecord that is a pointer to it. The second declares g_ppRecords to be a pointer to a pStudentRecord. In other words, a pointer to a pointer to a struct.
It's probably easier to think of the second as an "array of pointers". As such, g_ppRecords[0] may point to a pStudentRecord and g_ppRecords[1] to another one. (Which, in turn, point to a record struct.)
In order to add to it, you will need to know how it stores the pointers, that is, how one might tell how many pointers are stored in it. There either is a size somewhere, which for size N, means at least N * sizeof(pStudentRecord*) of memory is allocated, and g_ppRecords[0] through g_ppRecords[N-1] hold the N items. Or, it's NULL terminated, which for size N, means at least (N+1) * sizeof(pStudentRecord*) of memory is allocated and g_ppRecords[0] through g_ppRecords[N-1] hold the N items, and g_ppRecords[N] holds NULL, marking the end of the string.
After this, it should be straightforward to create or add to a g_ppRecords.
A struct is a compound data type, meaning that it's a variable which contains other variables. You're familiar with Objective C, so you might think of it as being a tiny bit like a 'data only' class; that is, a class with no methods. It's a way to store related information together that you can pass around as a single unit.
Typedef is a way for you to name your own data types as synonyms for the built-in types in C. It makes code more readable and allows the compiler to catch more errors (you're effectively teaching the compiler more about your program's intent.) The classic example is
typedef int BOOL;
(There's no built-in BOOL type in older ANSI C.)
This means you can now do things like:
BOOL state = 1;
and declare functions that take BOOL parameters, then have the compiler make sure you're passing BOOLs even though they're really just ints:
void flipSwitch(BOOL isOn); /* function declaration */
...
int value = 0;
BOOL boolValue = 1;
flipSwitch(value); /* Compiler will error here */
flipSwitch(boolValue); /* But this is OK */
So your typedef above is creating a synonym for a student record struct, so you can pass around student records without having to call them struct StudentRecord every time. It makes for cleaner and more readable code. Except that there's more to it here, in your example. What I've just described is:
typedef struct {
char * firstName;
char * lastName;
int id;
float mark;
} StudentRecord;
You can now do things like:
StudentRecord aStudent = { "Angus\n", "Young\n", 1, 4.0 };
or
void writeToParents(StudentRecord student) {
...
}
But you've got a * after the typedef. That's because you want to typedef a data type which holds a pointer to a StudentRecord, not typedef the StudentRecord itself. Eh? Read on...
You need this pointer to StudentRecord because if you want to pass StudentRecords around and be able to modify their member variables, you need to pass around pointers to them, not the variables themselves. typedefs are great for this because, again, the compiler can catch subtle errors. Above we made writeToParents which just reads the contents of the StudentRecord. Say we want to change their grade; we can't set up a function with a simple StudentRecord parameter because we can't change the members directly. So, we need a pointer:
void changeGrade(StudentRecord *student, float newGrade) {
student->mark = newGrade;
}
Easy to see that you might miss the *, so instead, typedef a pointer type for StudentRecord and the compiler will help:
typedef struct { /* as above */ } *PStudentRecord;
Now:
void changeGrade(PStudentRecord student, float newGrade) {
student->mark = newGrade;
}
It's more common to declare both at the same time:
typedef struct {
/* Members */
} StudentRecord, *PStudentRecord;
This gives you both the plain struct typedef and a pointer typedef too.
What's a pointer, then? A variable which holds the address in memory of another variable. Sounds simple; it is, on the face of it, but it gets very subtle and involved very quickly. Try this tutorial
This defines the name of a pointer to the structure but not a name for the structure itself.
Try changing to:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
} StudentRecord;
StudentRecord foo;
StudentRecord *pfoo = &foo;

Resources