So, this is my code:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
struct person{
char name[18];
int age;
float weight;
};
int main()
{
struct person *personPtr=NULL, person1, person2;
personPtr=(struct person*)malloc(sizeof*(struct person));
assert (personPtr!=NULL);
personPtr = &person1; // Referencing pointer to memory address of person1
strcpy (person2.name, "Antony"); //chose a name for the second person
person2.age=22; //The age of the second person
person2.weight=21.5; //The weight of the second person
printf("Enter a name: ");
personPtr.name=getchar(); //Here we chose a name for the first person
printf("Enter integer: ");
scanf("%d",&(*personPtr).age); //Here we chose the age of the first person
printf("Enter number: ");
scanf("%f",&(*personPtr).weight); //Here we chose the weithgt of the first person
printf("Displaying: "); //Display the list of persons
printf("\n %s, %d , %.2f ", (*personPtr).name, (*personPtr).age,(*personPtr).weight); //first person displayed
printf("\n %s, %d , %.2f",person2.name, person2.age, person2.weight); //second person displayed
free(personPtr);
return 0;
}
I get two errors and I don't know why. Firstly, I don't think that I allocated the memory right, the first error is on the next line:
personPtr=(struct person*)malloc(sizeof*(struct person));
It says that:
[Error] expected expression before ')' token
The second error that I get is on the line
personPtr.name=getchar();
Why cant I assign a name using getchar for a structure? The error is:
[Error] request for member 'name' in something not a structure or union
sizeof*(struct person) is a syntax error. It is seen by the compiler as an attempt to apply the sizeof operator to *(struct person). Since you can't dereference a type, the compiler complains. I think you meant to write the following:
personPtr = malloc(sizeof *personPtr);
It's the idiomatic way to allocate whatever personPtr is pointing to. Now the type is specified only where the pointer is defined, and that's a good thing. You also don't need to cast the result of malloc, since void* is implicitly convertible to any pointer type.
The second error is two-fold:
name is a fixed sized array. You cannot assign to an array using the assignment operator. You can only assign to each individual element.
getchar returns a single character, not a string as you seem to expect. To read a string, you can use scanf("%17s", personPtr->name). The 17 is the size of your buffer - 1, to protect against buffer overflow when scanf adds a NUL terminator to the string.
Related
This question already has answers here:
error: function returns address of local variable
(8 answers)
Closed 4 years ago.
I've been trying to write a program to solve a problem (ex. 19, Chapter 10 'C How to Program' 8th Ed, Deitel & Deitel), but I'm having a lot of trouble trying to identify the source of an issue I'm having.
I've been trying to pass some data to a function 'setData', which assigns the various values passed in to the members of a structure 'HealthProfile'. This seems to be happening successfully, and the function returns a pointer to a struct object to main. The pointer is then passed to function 'printStruct', and this is where the problem occurs. Each time the pointer is passed to the function, the function seems to be altering the values stored in each of the structure members, but I don't know why. I'm not trying to alter the member values, the point of passing the pointer to the structure to each function is so that the functions have access to the values contained in the members (my actual program has other functions, but I haven't included them because I'm still working on them, plus the issue I'm having is illustrated by function 'printStruct' alone.
Can anyone tell me where I've gone wrong?
I have tried a lot of different things, but nothing seems to work. I suspect that maybe the solution to the problem is that I should be passing a pointer to a pointer to the functions instead of a pointer, but I haven't had any luck in trying to fix the program this way. I also thought maybe I should be declaring the structure members as constant, but again no luck.
I've included a few printf statments in main to illustrate that the value of the pointer hasn't changed, but the value of the members of the structure have after the first call of function 'printStruct' (if printStruct is called a second time, a segmentation fault occurs).
#include <stdio.h>
typedef struct {
char *firstName;
char *lastName;
char *gender;
int birthDay, birthMonth, birthYear;
double height, weight;
} HealthProfile;
HealthProfile * setData(char first[20], char last[20], char gender[2],
int BirthDay, int BirthMonth, int BirthYear,
double Height, double Weight);
void printStruct(HealthProfile * variablePtr);
int main(void)
{
char FirstName[20], LastName[20], Gender[2];
int age, BirthDay, BirthMonth, BirthYear, maxRate = 0, targetRate = 0;
double bmi, Height, Weight;
HealthProfile *variablePtr;
puts("\n** Health Profile Creation Program **");
printf("\n%s\n\n%s", "Enter First Name", "> ");
scanf("%s", FirstName);
printf("\n%s\n\n%s", "Enter Last Name", "> ");
scanf("%s", LastName);
printf("\n%s\n\n%s", "Enter Gender (M/F)", "> ");
scanf("%s", Gender);
printf("\n%s\n\n%s", "Enter date of birth (dd/mm/yyyy)", "> ");
scanf("%d/%d/%d", &BirthDay, &BirthMonth, &BirthYear);
printf("\n%s\n\n%s", "Enter Height (m)", "> ");
scanf("%lf", &Height);
printf("\n%s\n\n%s", "Enter Weight (kg)", "> ");
scanf("%lf", &Weight);
variablePtr = setData(FirstName, LastName, Gender, BirthDay,
BirthMonth, BirthYear, Height, Weight);
printf("Address pointer: %p\n", variablePtr);
printf("Address pointer (deref): %p\n", variablePtr->firstName);
printf("Address pointer (deref): %p\n", variablePtr->lastName);
printStruct(variablePtr);
printf("Address pointer (deref): %p\n", variablePtr->firstName);
printf("Address pointer (deref): %p\n", variablePtr->lastName);
/* printStruct(variablePtr); */
}
HealthProfile * setData(char first[20], char last[20], char gender[2],
int BirthDay, int BirthMonth, int BirthYear,
double Height, double Weight)
{
HealthProfile profile, *profilePtr;
profilePtr = &profile;
profile.firstName = first;
profile.lastName = last;
profile.gender = gender;
profile.birthDay = BirthDay;
profile.birthMonth = BirthMonth;
profile.birthYear = BirthYear;
profile.height = Height;
profile.weight = Weight;
return profilePtr;
}
void printStruct(HealthProfile * variablePtr)
{
printf("\n%s%s\n%s%s\n%s%s\n%s%d/%d/%d\n%s%.2lfm\n%s%.1lfkg\n",
"First Name: ", variablePtr->firstName,
"Last Name: ", variablePtr->lastName,
"Gender: ", variablePtr->gender,
"DOB: ", variablePtr->birthDay, variablePtr->birthMonth,
variablePtr->birthYear,
"Height: ", variablePtr->height,
"Weight: ", variablePtr->weight);
}
Based on the way I've written the code, I was expecting the structure pointer passed to 'printStruct' not to be changed after the member values are printed. I would think I could call the function multiple times with no alteration to member values, but after just one call things are changed.
The Problem here is, that your pointer points to an address on the stack, which means, it's 'lifetime' or scope ends, when the Function setData returns. The next calls' stackframe overwirtes in part or whole the place in memory where your pointer points to. This leads to random and sometimes possibly correct output.
To solve this either allocate memory in the heap, instead of pointing to the address of a local variable ( malloc ) or declare a local variable im Main() and pass a pointer to setData.
Both solutions will prevent the issue you Are having.
Your problem is the time local variables are valid:
Both function arguments and local variables are only present in memory as long as the corresponding function is being executed. When the function has finished, the variables become invalid and may be overwritten with other data.
Now let's look at the following part of your code:
... setData( ... )
{
HealthProfile profile, *profilePtr;
profilePtr = &profile;
...
return profilePtr;
}
profilePtr contains a pointer to the local variable profile. As soon as the function setData has finished, this variable is no longer valid and may be overwritten.
The pointer profilePtr (returned by the function) will point to the memory where the variable profilePtr was located before. In other words: The value of the pointer profilePtr also becomes invalid because it points to a variable which no longer exists.
Maybe you have luck and the memory is not needed and the variable is not overwritten. But with a certain probability the function printf will need that memory and overwrite that (no longer valid) variable.
You might try this:
variablePtr = setData( ... );
printf("BirthDay (first time): %d\n", variablePtr->BirthDay);
printf("BirthDay (second time): %d\n", variablePtr->BirthDay);
With a high probability the following will happen:
printf will need the memory occupied by profile and therefore overwrite the data. However, in both lines above the value of BirthDay will first be read from the structure before the function printf is actually called.
Therefore the first printf will print the correct value of BirthDay while the second printf will print a wrong value.
So the primary objective here is to take input from the user and store it in an array where each element in the array is a struct srecord. I would like to be able to retrieve the strings fname and lname as well as the score. This is crucial because I am going to also design other methods that will calculate the average of all students in the array and tell which students have the highest or lowest score.
For example in fill_in_srecord_array, if I wanted to print out the information in a[i] after running fill_in_srecord, would this be the proper line?
printf("%s %s: Score= %d\n", a[i].fname, a[i].lname, a[i].score);
But this does not compile, so what is wrong here?
Is my fill_in_srecord method working properly and actually filling in the array properly?
For future reference, what is the best way to access variables from a struct being stored in an array?
#include <stdio.h>
#include <string.h>
struct srecord {
char fname[20]; /* first name */
char lname[20]; /* last name */
int score;
};
void fill_in_srecord(struct srecord *r){
struct srecord new_student; //declare a new student record
r = &new_student; //assign a value to the pointer
printf("Enter student first name: "); //request input
scanf("%s", r->fname);
printf("First: %s",r->fname);
printf("\nEnter student last name: ");
scanf("%s", r->lname);
printf("Last: %s",r->lname);
printf("\nEnter student score: ");
scanf("%d", &(r->score));
printf("Score: %d\n", r->score);
}
void fill_in_srecord_array(struct srecord a[], int len){
a[len];
//struct srecord *p; //srecord pointer
for(int i = 0; i<len; i++) {
fill_in_srecord(&a[i]);
}
}
int main(){
struct srecord students[2];
fill_in_srecord_array(students, 2);
exit (0);
}
The problem here is that in the fill_in_srecord function you do
struct srecord new_student;
r = &new_student;
This is problematic for three reasons:
First is that new_student is a local variable, and it will go out of scope and disappear once the function returns. Any pointers to it will be stray pointers and using them will lead to undefined behavior.
The second problem actually makes the first problem moot, because when you pass a value to a function in C the values are copied and the function only gets a copy. Modifying a copy (like e.g. r = &new_student) will of course not modify the original.
The third problem is that when the function is called, you pass a pointer to a valid and existing instance of the srecord structure. There's simply no need for the new_student variable or the reassignment of r inside the function. Modifying r directly will be enough.
So the solution is simply to not have the two problematic lines.
There's another thing as well, the statement a[len]; that you have in the fill_in_srecord_array function it doesn't really do anything. But if it did anything it would lead to undefined behavior because you would index the array a out of bounds.
Right now you were making changes to local variable , which is not accessible out of function block and changes made to it are not done on the variable in calling function itself .
When you pass address of a[i] to function ,and if you make changes to that in function ,a[i] will be modified in the calling function itself . Because the changes will be made directly to content at its address , that is to itself .
What you need to do is write your function like this -
void fill_in_srecord(struct srecord *r){
/* struct srecord new_student; //declare a new student record */
/* r = &new_student; //assign a value to the pointer */
printf("Enter student first name: "); //request input
scanf("%s", r->fname);
printf("First: %s",r->fname);
printf("\nEnter student last name: ");
scanf("%s", r->lname);
printf("Last: %s",r->lname);
printf("\nEnter student score: ");
scanf("%d", &(r->score));
printf("Score: %d\n", r->score);
}
I just wrote this snippet of code and have passed values of integers in for when it scans the integer in, but am getting back the memory address of the int towards the end.. how do I display only the number that I just read in instead of it's address? Can I simplify this code snippet even more?
#include <stdlib.h>
#include <stdio.h>
typedef struct building {
char *blockName;
int blockNumber;
} building;
int main() {
building *blockA = (building*)malloc(sizeof(building));
building *blockB = (building*)malloc(sizeof(building));
blockA->blockName = (char*)malloc(25*sizeof(char*));
blockB->blockName = (char*)malloc(25*sizeof(char*));
blockA->blockNumber = (int)malloc(sizeof(int));
blockB->blockNumber = (int)malloc(sizeof(int));
printf("What is the name for your first block: ");
scanf("%s", (*blockA).blockName);
printf("What will be it's number: ");
scanf("%d", (*blockA).blockNumber);
printf("\n");
printf("What is the name for your second block: ");
scanf("%s", (*blockB).blockName);
printf("What will be it's number: ");
scanf("%d", (*blockB).blockNumber);
printf("\n");
printf("Your first block's name is %s. It's number is %d\n", (*blockA).blockName, (*blockA).blockNumber);
printf("Your second block's name is %s. It's number is %d\n", (*blockB).blockName, (*blockB).blockNumber);
printf("\n");
free(blockA->blockName);
free(blockB->blockName);
free(blockA);
free(blockB);
system("pause");
return 0;
}
The member
int blocknumber;
is a plain scalar integer, not a pointer. Use it directly, without allocating memory to it. This line:
blockA->blockNumber = (int)malloc(sizeof(int));
is very suspicious and your compiler should have warned you. (You do compile with warnings enabled, don't you?) You are tyring to store a pointer in an integer value, which will fail on machines where the size of a pointer is greater then the size of an int.
The remedy is not to allocate memory for a scalar, then
scanf("%d", &(*blockB).blockNumber);
(note the &), and then you will have the user input available as:
printf("It's number is %d\n", (*blockB).blockNumber);
On the other hand, the malloc for the string is right, because the string is an array of chars, in this case allocated on the heap and represented by a pointer to the first char.
Since building is defined as
typedef struct building {
char *blockName;
int blockNumber;
} building;
You shouldn't be doing this
blockA->blockNumber = (int)malloc(sizeof(int));
as the line building *blockA = (building*)malloc(sizeof(building)); will already have allocated space on the heap for the int blockNumber:
You can simply assign it
blockA->blockNumber = 1234;
Or prompt the user for it
scanf("%d", &(blockA->blockNumber));
I trying reach to array member using pointer.
Array's first member adress is 23fe20 ;
When I write '1' the program must show me to 23fe24 (because 23fe20+4*1=23fe24) but not working this way. Program output is : 23fe30..
I can use *(pointer+i) for reach to array member but I want reach with adress. How can I do that? Sorry for my english, thanks a lot :'(
int main(int argc, char *argv[]) {
int array[5]={46,85,111,1976,2};
int *pointer,indices;
pointer=array;
int i=0;
printf("Array members : ");
for(i=0;i<=4;i++){
printf("%d ",array[i]);
}
printf("\n\n Array's First member' : %x\n\n",&*pointer);
printf("Which array member do you want to reach? ");
scanf("%d",&indices);
printf("\n Your member adress : %x",pointer+sizeof(int)*indices);
return 0; }
The address you calculate using sizeof(int) is already done by the compiler for you. So your calculation make it point to elsewhere (as the same calculation is done twice). You can simply add a integral type to a pointer to get access to an element.
So do:
printf("\n Your member adress : %p",(void*) (pointer+indices));
You should also use %p in the other place where you print address.
The reason for the behavior you see is that in C, pointers have a type, and addition is defined to add that many members, not bytes.
Actually, the syntax array[i] is the same as *(array+i).
Thus, you either have to remove the multiplication by sizeof(int), or, if you really wanted to explore arithmetic on adresses, make pointer a char * instead, because a character is one byte.
Example:
char *cp;
int *ip;
ip = array;
cp = (char *) ip;
printf("%p\n%p\n", ip + 1, cp + 1);
would print, assuming array is at address 23fe20:
23fe24
23fe21
(Assuming that sizeof(int) == 4)
I am writing a simple program in c so I can understand better the language but I have a strange problem.
As you see from the code below I have only one loop that it exits when I insert 255 as a value. The problem is that when I select the first(insert option) and after I insert a name the program starts something like a looping and gives me all the time the selection screen...
#include<stdio.h>
#include<stdlib.h>
struct student{
char *name;
int id;
};
void insertStudent(void);
struct student * init(void);
int main(){
struct student *p;
int selectionCode=0;
while(selectionCode!=255){
printf("\nInsert students:1");
printf("\nDisplay students:2");
printf("\nExit:255");
printf("\n\nEnter selection:");
scanf("%d",&selectionCode);
p=init();
switch(selectionCode){
case 1:
insertStudent();
//printf("1\n");
break;
case 2:
//printf("2\n");
break;
case 255:
break;
}
}
//p->name="stelios";
//p->id=0;
//printf("Name:%s ID:%d",p->name,p->id);
//free(p);
//p=NULL;
return 0;
}
struct student *init(void)
{
struct student *p;
p=(struct student *)malloc(sizeof(struct student));
return p;
}
void insertStudent(void){
struct student *p;
p=init();
printf("Enter Name:");
scanf("%s",p->name);//return 1;
printf("Enter ID:");
scanf("%d",&p->id);
//printf("test");
}
Part of the problem may be that the code is not allocating memory for the name field in the structure. The init function allocates a new structure but does not initialize the name field. The insertStudent function then uses scanf to read into that uninitialized pointer. That results in writing to "random" memory and can result in any number of problems including an access violation.
Looks like you have a memory leak, I would pass p into insertStudent().
You also have a return 1; in the middle of the insertStudent() call, so it will be returning before finishing its job.
You have "return 1;" after you scan in the name. It looks like logically you should not be returning at that point, since you want to enter in the ID. Also, you declared the function as returning "void" so returning one is an error.
Edit: The real problem is that you never allocated space for the name string.
try to:
struct student *insertStudent(void){
struct student *p;
p=init();
printf("Enter Name:");
scanf("%s",p->name);
printf("Enter ID:");
scanf("%d",&p->id);
//printf("test");
return p;
}
On the main
case 1:
free(p);
p=insertStudent();
//printf("1\n");
On the init you have to allocate space for the name.
What a mess... :-)
You never malloc() a buffer for p->name, but you are filling if with the scanf().
That is corrupting the memory of your program.
Besides... In your functions you are using the variable p and in your main program as well.
This is NOT the same variable, but you seem to assume it is.
Another problem: return 1; after the scanf() aborts the insertStudent() function so "enter ID " is never executed.
It is a void function so it should not return a value, by the way. The compiler has probably issued a warning about that.
There is probably more wrong with it, but this is what I spot after giving it a quick once over.
You need to remove the "return 1;" from insertStudent, otherwise is will no compile.
You should initialize p->name with malloc and change "scanf("%s",p->name);" to "scanf("%s", &p->name);", because you need a pointer to *char.