How to properly update this field in struct in C - c

trying to remember the syntax for updating a pointer in a struct.
I have something like this for example.
typedef struct {
char *name;
}car;
And I have a function which is called
void update_Name(car *d, char *newname)
{
car->name = &newname;
}
Is that correct or would it just be simply newname?
Very straight forward dont worry about any other syntaxes or functions needed just wanted to know straight up how that would be updated. Thank you

That is not quite correct.
You have a char *newname function parameters. You have a char *name struct member. &newname creates a pointer to newname which would be char **. Not what you want.
You just want car->name = newname; That assigns a char* to a char*.
Always be sure to compile your programs with maximum warning levels. It will tell you when you assign mismatched pointers.
And also in code like this remember memory and pointer lifetimes. You are assigning a pointer to characters into a structure. Whatever that points to needs to survive at least as long as your car structure or your car->name will become a "dangling pointer" pointing to dead memory.

First, car->name is not correct because car is the name of a type, not a variable. You want d->name instead.
With that correction, the type of d->name is char *. You're attempting to assign an expression of type char ** to it which doesn't match.
newname is already of type char * which matches the type of d->name, so you can assign it directly.
d->name = newname;

Related

Initializing and accessing char array in struct

I cannot seem to find a way to initialize a struct without getting segmentation fault .
Here is the assignment `
int id = 5;
// scanf ("%10d", &id);
printf("Please give an name\n");
char *tmpName = (char*)malloc(MAXSTRING * sizeof(char));
fgets(tmpName,MAXSTRING,stdin);
student newStudent = (student){ .id = id , .name = tmpName };
printf("%d",newStudent.id);
printf("%s",newStudent.name);
`
And here is the struct itself
#define MAXSTRING 256
typedef struct{
char *name;
int id;
}student;
I can successfully initialize the struct , but I cannot get access to the name variable , any thoughts?
EDIT : Answers submitted at the time offered nothing , the problem was the way the struct was initialized
char tmpName[MAXSTRING] = {0};
scanf("%s",tmpName);
student newStudent = { .id = id };
strcpy(newStudent.name,tmpName );
This block fixed the issue , will close the topic.
You define a pointer
char *tmpName;
you do nothing to make it actually point to some useable space, especially there is no malloc() or similar.
The you have scanf() (if successful...) write to the pointer, but a string, not any meaningful address. I.e. if that string is not extremely short, you certainly write beyond.
scanf("%s",&tmpName);
Do not be surprised by segfaults, be surprised if there are none.
Later on you then read from where that weird non-pointer points to...
To solve, insert a malloc() after the pointer definition. Alternatively use fixed array of char as an input buffer.
Use the pointer itself, not its address, in scanf() to write the string into the malloced space. (Or the array identifier.)
The rest is the typical set of problems with having enough space, failing to scan, without checking return value etc. Here is a great set of basic hints for getting input right:
How to read / parse input in C? The FAQ
When you declare char name[MAXSTRING], you are telling your compiler that it will always have the exact length of MAXSTRING.
When the compiler hears that, he will most likely replace your string with a lot of static char members.
#define MAXSTRING 4
typedef struct{
char name[MAXSTRING];
int id;
}student;
Would be extended and compiled more like so :
#define MAXSTRING 4
typedef struct{
char name0;
char name1;
char name2;
char name3;
int id;
}student;
Although you would still need to access those using the syntax name[index], as you declared an array, the array pointer is in fact nowhere to be found. So you can't directly assign it.
This is basically what happens with any fixed-length array, they won't allow you to asign them since their content is directly stored in the stack or in the datastructure enclosing it.
You would need to declare.
typedef struct{
char *name;
int id;
}student;
To get a char array pointer of variable length that you can assignate.
That should answer your question, now, as stated by someone in your comment section, there are other things wrong in your code and even with the correct structure, you will probably be unnable to do what you want since scanf is probably returning an arror right now. ^^'
Try allocating the memory beforehand doing so :
char *yourstring = (char*)malloc(MAXSTRING * sizeof(char));
And of course, don't forget to free when you don't need either the string or your student structure :
free(yourstring);
Then again, there's another small issue with your assignement since you do something like this :
.name = *yourstring
While using pointers, prefixing them with * will access the value at the pointed address.
Supposing char *yourstring = "I love cats.";
Doing .name = *yourstring will result in .name being equal to 'I' character, which is first in the array pointed to by yourstring. (Most compiler would complain and ask you to cast.. do not do that.)
So what you really need to do is to assign the pointer to your .name array pointer.
.name = yourstring

C - Incompatible types in assignment - structs and character arrays

Alright so the gist of my situation is that I'm stuck receiving an incompatibles types in assignment when trying to initialize my struct. I am fairly new to C and understanding pointers proves quite the challenge for me but I have looked at similar questions to this error and tried different fixes and have had no luck so far. If someone could fix this for me, you would be my hero.
struct Employee {
char* name[100];
int birth_year;
int starting_year;
};
struct Employee* make_employee(char* name, int birth_year, int starting_year);
int main(){
//some main stuff code
}
struct Employee* make_employee(char* name, int birth_year, int starting_year){
struct Employee* newEmpl = (struct Employee*)malloc(sizeof(struct Employee));
newEmpl->name = name;
newEmpl->birth_year = birth_year;
newEmpl->starting_year = starting_year;
return newEmpl;
}
The assignment errors occurs on the name = name line. I don't know why.
Also if I switch that line with
strcpy(&(newEmpl->name), name);
I get:
warning: passing argument 1 of 'strcpy' from incompatible pointer type
I've tried to find the problem for 2 hours, and no luck, thought I'd give a shot here.
char* name[100];
is an array of pointers to char but:
char* name;
is a pointer to char.
Here:
newEmpl->name = name;
You are trying to assign a pointer to char to the array but you cannot in C assign a pointer to an array! In fact you cannot assign anything to an array in C.
Check you are using the correct types in your program. Are you sure you want to use char *name[100]; and not char name[100]; (an array of char)? Then to copy a string it, use strcpy or strncpy and not the = operator as you cannot assign something to an array.
In your structure, change
char* name[100]; //an array of pointers to character
to
char name[100]; // a character array
Then, in your make_employee() function, instead of
newEmpl->name = name; //arrays cannot be assigned
use
strcpy(newEmpl->name, name); // copy the contains of name to newEmpl->name
or
strncpy(newEmpl->name, name, 99); // limit to 99 elements only + terminating null
Notes:
Please do not cast the return value of malloc() and family.
Please check for the success of malloc() and family before using the returned pointer.

Pointer to pointer of struct field in C

I have:
typedef struct
{
int id;
Other_Struct *ptr;
} My_Struct;
Lets say I have the pointer abcd which its type is My_Struct.
How can I get the address of:
abcd->ptr
?
I mean the address of ptr itself (like pointer to pointer) and not the address which is stored in ptr.
Just use the & address of operator, like this
Other_Struct **ptrptr = &(abcd->ptr);
How about this:
&(abcd->ptr)
If I understood correctly, in this scenario you have My_Struct *abcd pointing to an address, and what you want is the address of a field inside this structure (it doesn't matter if this field is a pointer or not). The field is abcd->ptr, so its address you want is &abcd->ptr.
You can easily check this by printing the actual pointer values (the difference between the addresses should give you the offset of ptr inside My_Struct):
struct My_Struct {
int id;
void *ptr;
};
main()
{
struct My_Struct *abcd;
printf("%p %p\n", abcd, &abcd->ptr);
}
Update: If you want your code to be portable, standards-compliant, and past and future proof, you may want to add casts to void * to the printf() arguments, as per #alk's comments below. For correctness, you can also use a standard entry point prototype (int main(void) or int main(int argc, char **argv)) and, of course, include stdio.h to use printf().
The most unambiguous way to do it is thus:
My_Struct *abcd;
Other_Struct **pptr;
pptr = &(abcd->ptr);
I don't know if the parentheses are really necessary, and I don't care, because it's more readable this way anyway.

What does this snippet from Exercise 16 from "Learn C The Hard Way" mean?

I am learning C from this blog. Below is some code from the blog:
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
who->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
return who;
}
I have the following doubts:
Is Person_create the name of this function? How could a function name be a pointer? What does it signify?
Why strdup(String Duplicate) is used just for name, not other fields like height, age, etc.
For it would be clear the function declaration can be written the following way
struct Person * Person_create(char *name, int age, int height, int weight);
That is the function name is Person_create and the function returns an object of type struct Person *. As you can see in its definition the function returns who that is defined as
struct Person *who = malloc(sizeof(struct Person));
You could write even the function declaration for example like
struct Person * ( Person_create(char *name, int age, int height, int weight) );
Take into account that for example all the following declarations are equivalent
int *p;
int* p;
int * p;
As for the second your question then it seems that data member name is declared like
char *name;
You need to allcoate memory that will be pointed to by name that to store the string pointed by parameter name in this memory. Function strdup does two things. It allocates required memory and copies string pointed by the parameter to the allocated memory and returns pointer to that memory.
As for other data members of the structure then they are not pointers. They are objects (though a pointer is also an object but it points to other object that has to be stored somewhere). So you need not to allocate memory that to store data in these objects. The memory for these data members will be allocated when an instance of the structure will be created.
Person_create is a function. It could also be written as struct Person* Person_create which would be syntactically identical. Whether to put the space next to the type or next to the name is a a debate as old as the C language which I refuse to get involved in.
As you might have noticed, the name-string is a pointer. When you would do just who->name = name; you wouldn't copy the string. You would just copy the pointer to a string. The result would be that you have two pointers which point to the same string. Why is this a problem? Imagine you make some change the name in one of the structs. The change would then also affect the other struct. This is likely not your intention.
That's why you need strdup(). It stands for "string duplicate". It creates a copy of a string and returns a pointer to the newly created string which can then be handled independently from the original.
Person_create() is a function, which returns struct Person * (a pointer to a Person struct). It could also be written as following: struct Person * Person_create() or struct Person* Person_create().
strdup() is used only for the name variable, as name is the only string (char*/char array in C) variable in the Person struct.
So why do you need to use strdup() on char* and you do not have to use similar functions for types like int?
This is because in C you pass by value, meaning that you will pass a value of an int age (which you can assign using =) and a value of char*. The *char pointer points to same place in memory, which ends with \0 (symbol of string/char array termination in C). Therefore you have to use a separate function to copy all the characters between where char* name points to when passed to the function and the \0 (together with the \0).

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