Char array in a struct - incompatible assignment? [duplicate] - c

This question already has answers here:
Structure Problem in C
(12 answers)
Closed 4 years ago.
I tried to find out what a struct really 'is' and hit a problem, so I have really 2 questions:
1) What is saved in 'sara'? Is it a pointer to the first element of the struct?
2) The more interesting question: Why doesn't it compile?
GCC says "test.c:10: error: incompatible types in assignment" and I can't figure out why...
(This part has been solved by your answers already, great!)
#include <stdio.h>
struct name {
char first[20];
char last[20];
};
int main() {
struct name sara;
sara.first = "Sara";
sara.last = "Black";
printf("struct direct: %x\n",sara);
printf("struct deref: %x\t%s\n", *sara, *sara);
}
Thanks for your help!

This has nothing to do with structs - arrays in C are not assignable:
char a[20];
a = "foo"; // error
you need to use strcpy:
strcpy( a, "foo" );
or in your code:
strcpy( sara.first, "Sara" );

Or you could just use dynamic allocation, e.g.:
struct name {
char *first;
char *last;
};
struct name sara;
sara.first = "Sara";
sara.last = "Black";
printf("first: %s, last: %s\n", sara.first, sara.last);

You can also initialise it like this:
struct name sara = { "Sara", "Black" };
Since (as a special case) you're allowed to initialise char arrays from string constants.
Now, as for what a struct actually is - it's a compound type composed of other values. What sara actually looks like in memory is a block of 20 consecutive char values (which can be referred to using sara.first, followed by 0 or more padding bytes, followed by another block of 20 consecutive char values (which can be referred to using sara.last). All other instances of the struct name type are laid out in the same way.
In this case, it is very unlikely that there is any padding, so a struct name is just a block of 40 characters, for which you have a name for the first 20 and the last 20.
You can find out how big a block of memory a struct name takes using sizeof(struct name), and you can find out where within that block of memory each member of the structure is placed at using offsetof(struct name, first) and offsetof(struct name, last).

use strncpy to make sure you have no buffer overflow.
char name[]= "whatever_you_want";
strncpy( sara.first, name, sizeof(sara.first)-1 );
sara.first[sizeof(sara.first)-1] = 0;

sara is the struct itself, not a pointer (i.e. the variable representing location on the stack where actual struct data is stored). Therefore, *sara is meaningless and won't compile.

You can use strcpy to populate it. You can also initialize it from another struct.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct name {
char first[20];
char last[20];
};
int main() {
struct name sara;
struct name other;
strcpy(sara.first,"Sara");
strcpy(sara.last, "Black");
other = sara;
printf("struct: %s\t%s\n", sara.first, sara.last);
printf("other struct: %s\t%s\n", other.first, other.last);
}

The Sara structure is a memory block containing the variables inside. There is nearly no difference between a classic declarations :
char first[20];
int age;
and a structure :
struct Person{
char first[20];
int age;
};
In both case, you are just allocating some memory to store variables, and in both case there will be 20+4 bytes reserved. In your case, Sara is just a memory block of 2x20 bytes.
The only difference is that with a structure, the memory is allocated as a single block, so if you take the starting address of Sara and jump 20 bytes, you'll find the "last" variable. This can be useful sometimes.
check http://publications.gbdirect.co.uk/c_book/chapter6/structures.html for more :) .

You can try in this way. I had applied this in my case.
#include<stdio.h>
struct name
{
char first[20];
char last[30];
};
//globally
// struct name sara={"Sara","Black"};
int main()
{
//locally
struct name sara={"Sara","Black"};
printf("%s",sara.first);
printf("%s",sara.last);
}

Related

how to use pointers in structures?

I used pointer while printing structure elements but its working without using pointer in the print statement but shouldn't we use pointers to gather the element from the variable address why is it different in the structure case and its different in string also . Can anyone tell me why is that ?
#include <stdio.h>
int main(){
struct books{
char name[10];
int page;
};
struct books b1={"book1",1};
struct books *ptr;
ptr=&b1;
printf("%s %d",ptr->name,ptr->page);
}
printf("%s %d",*ptr->name,*ptr->page);
is wrong. A->B means (*A).B. You should do either
printf("%s %d",ptr->name,ptr->page);
or
printf("%s %d",(*ptr).name,(*ptr).page);
What MikeCAT said.
Beware though that an array would also be a pointer so *ptr->name would compile but will produce the first character of 'name'.
struct books{
char name[10];
int page;
};
ptr=&b1;
printf("%c",*ptr->name);
Pointers used when the object is too big and copying such object vastes time. But in your struct it takes 10 bytes for char array + 4 bytes for int and it's not a problem. In 64 bit machine pointers take 8 bytes in 32 bit 4 bytes. Suppose you have a big a struct and per object it takes 50 bytes of memory if you copy it will take more space and will be slower and by copying a brand new object will be created and that won't change anything in original one.
Let's see in practice when pointers can be used:
#include <stdio.h>
struct person{
char name[10];
int age;
};
void grow(struct person p) {
++p.age;
}
int main(){
struct person Mike = { "Mike", 20 };
grow(Mike);
printf("Name: %s\tAge: %d", Mike.name, Mike.age);
}
OUTPUT:
Name: Mike Age: 20
This code won't change age of Mike because void grow(struct person p) function copies struct person by creating a new object then increments age and at the end destroys struct person p. If you pass it as pointer then Mike will be modified.

struct variable cannot access struct members

I was working on a a few basic implementations of structures in C. The goal of my program is to access the members of struct using variables instead of pointers.
This is my program:
#include<stdio.h>
#include<string.h>
struct oldvar{
char name[100];
int age;
float height;
};
void main()
{
struct oldvar DAD;
printf("\nThe old values are %s\n%d\n\f",DAD.name,DAD.age,DAD.height);
strcpy("Will Smith",DAD.name);
DAD.age = 50;
DAD.height = 170;
printf("The updated values are %s\n%d\n\f",DAD.name,DAD.age,DAD.height);
}
On implementing this, I got only the garbage values and no updates :
The old values are ⌡o!uC&uⁿ■a
3985408
How can I update my structure members using variables?
The line
strcpy("Will Smith",DAD.name);
is wrong.
According to strcpy(3) - Linux manual page:
char *strcpy(char *dest, const char *src);
The destination (where to write the copy) is the first argument and the source (what should be copied) is the second argument.
Therefore, the line should be
strcpy(DAD.name,"Will Smith");
Also using values of uninitialized non-static local variable invokes undefined behavior, allowing anything to happen.
For more safety, you should initialize the variable DAD before printing. In other words, the line
struct oldvar DAD;
should be (for example)
struct oldvar DAD = {""};
As mentioned in other answers, the first argument to strcpy() is the destination. Plus there were errors in printf too. It was supposed to be %f, not \f
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
struct oldvar {
char name[100];
int age;
float height;
};
int main(void)
{
struct oldvar DAD={"\n",0,0.0};
strcpy(DAD.name,"will Smith");
printf("\nThe old values are %s\n%d\n%f", DAD.name, DAD.age, DAD.height);
DAD.age = 50;
DAD.height = 170;
printf("The updated values are %s\n%d\n%f", DAD.name, DAD.age, DAD.height);
}
strcpy("Will Smith",DAD.name); --> strcpy(DAD.name, "Will Smith");
strcpy("Will Smith",DAD.name); will copy DAD.name to some constant memory that contain "Will Smith" (Read only memory part).
So that, your program will crash because there is an attempt to write on READ Only Memory part

C, Expression must be a modifiable lvalue (changing the value of a struct's member) [duplicate]

This question already has answers here:
Assigning strings to arrays of characters
(10 answers)
Closed 4 years ago.
I'm an extreme newbie, I'm just trying to learn.. this is my simple struct that I've created
struct Student{
char FirstName[20];
char LastName[20];
char StudentID[10];
char Password[20];}
Then I'm creating an array of pointers;
struct Student *StudentList[10];
I am then calling my "Register" function and passing the first element in the array as a parameter, for the reason of changing values to that specific struct element in the array, for example I want to change the student's details;
Register(&StudentList[0]);
Further on, my function;
void Register(struct Student *student);
void Register(struct Student *student) {student->FirstName = "John";}
This is a very simplified example and sorry for not being able to correctly paste in the code here.
But why am I getting an "expression must be a modifiable lvalue", when I try to assign a value.
You can't assign array types like that in C, and "John" is an array of type char[5].
strcpy(student->FirstName, "John");
would do it or, better still, something of the form
strncpy(student->FirstName, "John", 20);
so you avoid overrunning the char buffer.
The firstName field is an array, and arrays cannot be assigned to as a whole. That's what the error message is telling you.
Since you're copying a string into this array, you should use strcpy:
strcpy(student->FirstName, "John");
In C, you do not set strings using = (and you do not compare them using == either).
You must use the strcpy function:
strcpy( student->firstName, "John" );
First thing you forget to put semicolon at the end of struct declaration struct Student { };
Secondly, you are passing &StudentList[0], instead just pass StudentList[0] and allocate memory dynamically for that first.
Finally, student->FirstName = "John"; because student->FirstName is one char buffer and "John" also one buffer so you can't do A = B where A and B both are char buffer, instead use strcpy(A,B);
Here is sample example
struct Student{
char FirstName[20];
char LastName[20];
char StudentID[10];
char Password[20];
}; /* you forget to put semicolon */
void Register(struct Student *student) {
strcpy(student->FirstName,"John"); /* use strcpy() */
printf("%s\n",student->FirstName);
}
int main() {
struct Student *StudentList[10];
for(int index = 0;index < 10;index++) {
StudentList[index] = malloc(sizeof(struct Student)); /* allocate memory for each Student */
}
Register(StudentList[0]);
/* free the dynamically allocated memory */
return 0;
}

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

display a specified index of a pointer char*

I am trying to point on a specified character in a string contained on a structure
here my code
typedef struct{
char *name;
int age;
}PERSON, *person;
int main(){
person serenity;
serenity = (person)malloc(sizeof(PERSON));
strcpy(&(serenity->name),"Serenity");
printf("%c",*(&(serenity->name)+1));
}
here i wanted to display the second character which is 'e' but it shows 'n' instead
anyone can explain me what is wrong with this,
thank you
You have not allocated memory for name
typedef struct{
char *name;
int age;
}PERSON, *person;
int main(){
person serenity;
serenity = malloc(sizeof(PERSON));
serenity->name = malloc(sizeof("Serenity")); //<< Missing
strcpy((serenity->name),"Serenity");
printf("%c",*((serenity->name)+1)); // << Also you want the value in pointer name NOT its address
return 0;
}
Outputs e. Also since you tagged C there is no need to cast the return type of malloc.
Okay, okay... All of those answers aside, if you do not aim to change the characters inside the string "Serenity" in the future, you could just do the following:
#include <stdio.h>
typedef struct{
const char *name; // <-- added const
int age;
}PERSON, *person;
int main( ){
person serenity;
serenity = (person) malloc( sizeof( PERSON ) );
serenity->name = "Serenity"; // <-- simply assigned the pointer with the
// address to the array of constant characters
printf( "%c", *( serenity->name + 1 ) ); // <-- changed this
}
This statement
serenity = (person)malloc(sizeof(PERSON));
allocates the structure
typedef struct{
char *name;
int age;
}PERSON
however name is kept uninitialized and points somewhere in memory causing a crash when you copy to it.
So instead of
strcpy(&(serenity->name),"Serenity");
write
serenity->name = strdup("Serenity");
which is the same as
serenity->name = malloc(strlen("Serenity")+1);
strcpy(serenity->name,"Serenity");
don't forget to free that string as well later.
Try printf("%c",*(serenity->name+1));, also do strcpy(serenity->name,"Serenity");.
If you have a pointer char* name; you access the second element by doing name[1] or *(name+1). &name will give you the address where the pointer address of name is stored. This is not what you want here.
Another issue in your program is that you never allocate memory for the variable name. You need a serenity->name = (char*)malloc(128);. But using an arbitrary length like 128 is very dangerous in combination with strcpy. Use strncpy instead of strcpy to work around this.

Resources