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
Related
I want to return the name of the smallest city population-wise, if it is the second city. (Please don't mind the if statement, I know it's bland), the missing return is what bothers me.
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
typedef struct Coordinate{
int x,y;
}Coordinate;
typedef struct city{
char name[20];
int population;
Coordinate coordinates;
}city;
char *rSmallestCity(city **cl, int n)
{
char *rtrn = NULL;
if(cl[n-2]->population>cl[n-1]->population)
{
rtrn = &cl[n-1]->name;
}
return rtrn;
}
int main()
{
city c1 ={.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4};
city c2 ={.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2};
city *clist[2];
clist[0]=&c1;
clist[1]=&c2;
printf("\n%s is smallest\n",rSmallestCity(clist,2));
}
warning: assignment to 'char ' from incompatible pointer type 'char ()[20]' [-Wincompatible-pointer-types]|
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
A good question. And your assumption is correct. Creating a variable inside a function it's existence ends upon leaving the function. But in this case, because the struct member name is already a char * you do not need to create another variable. Just return c1.name. (see code example below.)
A few other suggestions:
In the struct declaration:
typedef struct Coordinate{
int x,y;
}Coordinate;
You've used the same symbol (Coordinate) for the struct name, and for it's typedef. This is not a good practice. If you need both a struct name and a typedef, pick different symbols. BTW, in this this example, only one or the other is needed. Say you pick the typedef, then the struct is completely defined by:
typedef struct {
int x,y;
}Coordinate;
That suggestion applies to both struct declarations in your example code.
The signatures for the main function do not include int main(){...} rather
int main(void){..., return 0;} and int main(int argc, char *argv[]){..., return 0;}
The following code example illustrates some of the other suggestions for improvements in comments under your post,
typedef struct {
int x,y;
}Coordinate;
typedef struct {
char name[20];
int population;
Coordinate coordinates;
}city;
//return char * rather than char to allow for full null terminated char array (string)
char * rSmallestCity(city c1[],int cityCount)//generisize function prototype to
{ //to easily accommodate bigger arrays if needed
long long size, sizeKeep = 8e9; //index and population. initialize larger than possible population
int indexKeep = 0;
//note you do not need to define a char *, the struct already contains one
for(int i=0; i<cityCount; i++)//use a loop rather than a single comparison, keep the smalles
{
size = c1[i].population;
sizeKeep = (size < sizeKeep) ? indexKeep = i, size : sizeKeep;
}
printf("\n%s\n",c1[indexKeep].name);
return c1[indexKeep].name;
};
int main(void)//use minimum signature for main, and call return before leaving.
{
//combining your original declarations and assignments for struct
//into a single declaration/definition.
city c1[] = {{.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4},
{.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2}};
int cityCount = sizeof(c1)/sizeof(c1[0]);
printf("\n%s is smallest",rSmallestCity(c1, cityCount));
return 0;
};
The solution that I originally left in comment under OP (remove & in the line &cl[n-1]->name;) needs some explanations to avoid problems later.
(It is an educational answer not a full answer on pointers, array decay, ... And many examples can be found on stackoverflow. I tried to simplify)
Try this simple code.
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1);
printf("%p\n",&myString1);
}
The output is the same, but an array name and the address of an array name are not the same. The array name is evaluated to the address of its first element. So it works in your case but a warning is issued during compilation and it is very important. Firstly, do not remove compilation warnings.
Now, try this code :
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1+1);
printf("%p\n",&myString1+1);
}
The outputs are different. Because myString1 is evaluated to char* and &myString1 to char [25]. So +1, in the first, case adds one (sizeof char) to the pointer and in the other case, it adds 25.
Delete the "&" in the line:
rtrn = &cl[n-1]->name;
To extremely simplify, you assigned an "address of char[]" to a char*, but array syntax makes it work regardless.
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
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.
I have a C struct defined as follows:
struct Guest {
int age;
char name[20];
};
When I created a Guest variable and initialized it using the following:
int guest_age = 30;
char guest_name[20] = "Mike";
struct Guest mike = {guest_age, guest_name};
I got the error about the second parameter initialization which tells me that guest_name cannot be used to initialize member variable char name[20].
I could do this to initialize all:
struct Guest mike = {guest_age, "Mike"};
But this is not I want. I want to initialize all fields by variables. How to do this in C?
mike.name is 20 bytes of reserved memory inside the struct. guest_name is a pointer to another memory location. By trying to assign guest_name to the struct's member you try something impossible.
If you have to copy data into the struct you have to use memcpy and friends. In this case you need to handle the \0 terminator.
memcpy(mike.name, guest_name, 20);
mike.name[19] = 0; // ensure termination
If you have \0 terminated strings you can also use strcpy, but since the name's size is 20, I'd suggest strncpy.
strncpy(mike.name, guest_name, 19);
mike.name[19] = 0; // ensure termination
mike.name is a character array. You can't copy arrays by just using the = operator.
Instead, you'll need to use strncpy or something similar to copy the data.
int guest_age = 30;
char guest_name[20] = "Mike";
struct Guest mike = { guest_age };
strncpy(mike.name, guest_name, sizeof(mike.name) - 1);
You've tagged this question as C++, so I'd like to point out that in that case you should almost always use std::string in preference to char[].
Actually you can statically initialise this struct:
struct Guest {
int age;
char name[20];
};
Guest guest = { 30, {'M','i','k','e','\0'}};
Each element of the array must be set explictly and this cannot be done using c-strings. If the struct is defined with a char* name then we can do this:
struct Guest {
int age;
char* name;
};
Guest guest = { 30, "Mike"};
You can statically allocate a struct with a fixed char[] array in C. For example, gcc allows the following:
#include <stdio.h>
typedef struct {
int num;
char str[];
} test;
int main(void) {
static test x={.num=sizeof("hello"),.str="hello"};
printf("sizeof=%zu num=%d str=%s\n",sizeof(x),x.num,x.str);
return 0;
}
And it does the right thing (though beware of the sizeof(x): it returns 4 on my machine; not the length of the total statically allocated memory).
This does not work for structs allocated from the stack, as you might suspect.
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);
}