I am trying to create a contact list using structures and functions. Currently my code compiles but the members of the struct are not being modified outside of the function like I am trying to do. Here is my code(removed some lines for length)
#include <stdio.h>
#include <stdlib.h>
struct ContactInfo
{
char fname[50];
char lname[50];
};
struct ContactInfo gc;
void getContactInfo(struct ContactInfo gc)
{
printf("First Name: ");
scanf("%s", gc.fname);
printf("\nLast Name: ");
scanf("%s", gc.lname);
}
void showContactInfo(struct ContactInfo gc)
{
printf("* First Name: %s \n", gc.fname);
printf("* Last Name: %s \n", gc.lname);
}
int main()
{
getContactInfo(gc);
showContactInfo(gc);
return 0;
}
For getContactInfo, you need to pass a pointer to the struct:
void getContactInfo( struct ContactInfo *gcptr )
{
printf("First Name: ");
scanf("%s", gcptr->fname);
printf("\nLast Name: ");
scanf("%s", gcptr->lname);
}
Since you're trying to modify the contents gc, you need to pass a pointer to it to the function. Remember that C passes all arguments by value, so the called function creates a separate, duplicate object that receives the value of the parameter. Your code is modifying that duplicate object, which has no effect on the actual parameter.
The -> operator is used when the operand is a pointer to a struct or union type - it implicitly dereferences the pointer before accessing the particular member. It's equivalent to writing (*gcptr).fname and (*gcptr).lname, while being a little easier on the eyes.
You'd call this function as
getContactInfo( &gc );
For showContactInfo, you can leave it as it is since you're not trying to modify the parameter. However, a lot of people like to pass pointers to structs to save memory (you're not building a copy of the struct in the called function). If you want to use a pointer, I would recommend using the const keyword like so:
void showContactInfo( const struct ContactInfo *gcptr )
{
printf("* First Name: %s \n", gcptr->fname);
printf("* Last Name: %s \n", gcptr->lname);
}
The const keyword tells the compiler to yell at me if I try to modify the contents of the object gcptr points to in the showContactInfo function. Like getContactInfo above, you'd call it as
showContactInfo( &gc );
Note that I changed the argument names to gcptr just to help distinguish between the formal argument in the function definition and the actual argument in the function call. I normally don't like putting any kind of type information in a variable or argument name, but you can use whatever naming convention you like.
The C way for doing this is just plain old pointers:
void showContactInfo(struct ContactInfo* gc)
{
printf("* First Name: %s \n", gc->fname);
printf("* Last Name: %s \n", gc->lname);
}
Other than having to use the arrow operator -> to access properties it's basically the same.
C itself does not have references like C++ does.
The getContactInfo function is supposed to return values, but you pass values in instead.
The most natural way to get data out of a function is to use the return value. Also you should not use global variables for passing data. The code could look like:
struct ContactInfo getContactInfo(void)
{
struct ContactInfo g = { 0 }; // ensure no garbage in case input fails
printf("First Name: ");
scanf("%49s", g.fname);
printf("Last Name: ");
scanf("%49s", g.lname);
return g;
}
with the code in main being:
struct ContactInfo gc = getContactInfo();
showContactInfo(gc);
Related
So I've been looking at structures, functions and pointers for days now. I just cant wrap my head around structures good enough to do what I want...
I was trying to write a function, which was originally going to receive user input (taken with fgets) as an argument. I have put that aside now, and just decided to give the function a single argument. That argument will be the name of a struct, and I'll use that name to access it's variables and print them the way I want.
typedef struct
{
int hp;
char *name;
} bare;
bare example;
void print_info(char *name);
int main()
{
example.hp = 5;
strcpy(example.name,"John");
print_info("example");
}
void print_info(char *name)
{
printf("The hp of %s is %d", (*name), (*name)->hp);
}
Whatever bloody thing I put there instead of char *name, it always ended up giving me the error "error: struct or union expected"! I tried struct bare **name and (*name)->hp/(*name).hp, char *name/**name and *&name.hp, *&name->hp, every possible solution I could think of..! i think they all turned out to be nonsense... I just cant wrap my head around pointers and structs enough to do this! A little help please? I searched high and low on function arguments, pointers and structs, yet couldn't find a solution/question like mine..
First, it's better to declare your struct this way:
typedef struct bare {
int hp;
char *name;
} bare;
Second, avoid global variable as much as you can. I don't see the point of declaring example in the global namespace since you are using it only inside main().
Third, this line has a problem:
strcpy(example.name, "John");
You are attempting to copy "John" to an uninitialized pointer (example.name) that points to some random memory address. You have to either allocate enough space using malloc() (and free it when you're done with it), or use a fixed-length array. Moreover, it's better to use strncpy() because it allows to specify the maximum number of characters to copy. This way you avoid the risk of buffer overflow.
Fourth, to avoid copying your entire struct to print_info() (in fact, any other struct to any other function), you should pass its address.
With all that said, here is how your code should be written:
#include <stdio.h>
#include <string.h>
typedef struct bare {
int hp;
char name[100]; // Make sure it has enough space, or use malloc() if you don't know how much it will hold initially
} bare;
void print_info(bare *name);
int main(void)
{
bare example; // Declare it inside main()
example.hp = 5;
strncpy(example.name, "John", sizeof example.name); // This works and is safe
print_info(&example);
}
void print_info(bare *name)
{
printf("The hp of %s is %d", name->name, name->hp);
}
Output:
The hp of John is 5
I think what you wish to do is this:
#include <stdio.h>
#include <string.h>
typedef struct {
int hp;
char *name;
} bare;
bare example;
void print_info(bare *name);
int main() {
example.hp = 5;
strcpy(example.name, "John");
print_info(&example);
}
void print_info(bare *name) {
printf("The hp of %s is %d", name->name, name->hp);
}
Or if you want to pass example by value:
#include <stdio.h>
#include <string.h>
typedef struct {
int hp;
char *name;
} bare;
bare example;
void print_info(bare name);
int main() {
example.hp = 5;
strcpy(example.name, "John");
print_info(example);
}
void print_info(bare name) {
printf("The hp of %s is %d", name.name, name.hp);
}
Why did your code not work?
print_info had an incorrect argument data type. What you wanted was to pass an object of bare or perhaps a pointer to an object of bare, but you were instead passing a variable of type char *.
The arrow operator is used on pointers. Maybe take a look at Arrow operator (->) usage in C.
You wanted to pass in a string typed in by the user.
I was trying to write a function, which was originally going to receive user input (taken with fgets) as an argument. I have put that aside now, and just decided to give the function a single argument.
This explains why you pass in a char * to your function. The input value was originally going to be read from fgets. In your program, you passed in the name of your variable.
bare example;
/* ... */
print_info("example");
To do a dynamic lookup on a symbol name, use dlsym.
As I suggested in comments, if you want to be able to look up the name of a variable to find the associated object, you can use dlsym so long as you are on a POSIX system (like Linux). For example:
// Need to inlcude <dlfcn.h> and link with -ldl
// Make local variables findable with -rdynamic
void print_info(char *name)
{
bare *p = dlsym(0, name);
if (p != NULL)
printf("The hp of %s is %d", p->name, p->hp);
else
printf("%s not found!\n", name);
}
So long as you include <dlfcn.h> and use -ldl when linking the program, and you make your symbol table visible (with -rdynamic on GCC), the program will find the pointer to your example variable. (Try it online!)
But you probably meant to do a lookup by name.
However, you seemed to have mixed some things up. Usually, the user will not care what names you have used for the variables in your program. You would never expect fgets to give you "example" because that is not what the user would type in.
You probably meant to search for the bare record that matches the name parameter of bare. In your case, "John".
print_info("John");
Normally, you would have a table of bares that you would look over and check for a match. However, in your simplified example, there is only one to check.
bare * find_bare(char *name)
{
if (strcmp(name, example.name) == 0) return &example;
return NULL;
}
void print_info(char *name)
{
bare *p = find_bare(name);
if (p != NULL)
printf("The hp of %s is %d", p->name, p->hp);
else
printf("%s not found!\n", name);
}
It isn't hard to create and search a table of bare.
In this case, you could probably simple create an array of bare to represent your collection that you would search over.
#define BARE_TABLE_SIZE 50
bare table_example[BARE_TABLE_SIZE];
Assuming you add the code to populate your table, you could use a simple loop to search for a matching name.
bare * find_bare(char *name)
{
for (int i = 0; i < BARE_TABLE_SIZE; ++i)
{
if (strcmp(name, table_example[i].name) == 0)
return &table_example[i];
}
return NULL;
}
Your example.name was an uninitialized pointer.
Finally, the most egregious error in your program is the attempt to call strcpy on an uninitialized pointer. One solution is to allocate new memory to hold the new name and assign the location of the new name to the pointer. POSIX systems (like Linux) supply a function called strdup that creates a copy of the input for you, in newly allocated memory.
example.name = strdup("John");
Since the memory is allocated by malloc, you would need to call free on the pointer if example is ever recycled for a new name.
This function is supposed to save data to a library.books_count instance of a dynamic array of pointers to structures. Yet it does not. A similar function addexistingBooks() does it flawlessly. What is the problem in realloc()?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char book_name[32];
char book_genre[32];
char author[32];
int page_count;
float price;
}Sbook;
typedef struct
{
char library_name[32];
Sbook * bookp;
int books_count;
}Slib;
void menu(char String[50]);
void addexistingBooks(Slib library, int i);
void addBook(Slib library, int i);
int main()
{
Slib library;
int i=0;
char Choice[30];
printf("Enter amount of books inside the library: ");
scanf("%d", &(library.books_count));
library.bookp = (Sbook *)calloc(library.books_count,sizeof (Sbook));
fflush(stdin);
addexistingBooks(library, i);
menu(Choice);
if(strcmp(Choice,"add")==0)
{
addBook(library, i);
}
free(library.bookp);
return 0;
}
void menu(char String[30])
{
printf("Welcome to the library. If you read about heresy, prepare to be purged \n");
printf("Please choose a command, by writing the appropriate command: \n");
printf("1. Write 'add' to add a book. \n");
printf("2. Write 'remove' to remove a book. \n");
printf("3. Write 'redact' to redact a book. \n");
printf("4. Write 'Sort by criteria' to sort the books, where criteria can stand for: 1.bookname, 2.author, 3.genre, 4.price. \n");
printf("Enter your command: ");
gets(String);
}
void addexistingBooks(Slib library, int i)
{
for(i=0;i<library.books_count;i++)
{
printf("Enter the name of the book: \n");
fgets(library.bookp[i].book_name,32,stdin);
printf("Enter the genre of the book: \n");
fgets(library.bookp[i].book_genre,32,stdin);
printf("Enter the author of the book: \n");
fgets(library.bookp[i].author,32,stdin);
printf("Enter the page count of the book: \n");
scanf("%d", &(library.bookp[i].page_count));
printf("Enter the price of the book: \n");
scanf("%f", &(library.bookp[i].price));
fflush(stdin);
}
}
void addBook(Slib library, int i)
{
(library.books_count)++;
realloc(library.bookp,library.books_count);
fflush(stdin);
if(library.bookp==NULL)
{
exit(1);
}
printf("Enter the name of the book: \n");
fgets(library.bookp[i].book_name,32,stdin);
printf("Enter the genre of the book: \n");
fgets(library.bookp[i].book_genre,32,stdin);
printf("Enter the author of the book: \n");
fgets(library.bookp[i].author,32,stdin);
printf("Enter the page count of the book: \n");
scanf("%d", &(library.bookp[i].page_count));
printf("Enter the price of the book: \n");
scanf("%f", &(library.bookp[i].price));
fflush(stdin);
}
Your code contains several mistakes.
Lets start from the "non-blocking" mistakes. Those that, even if they can be really critical and have to be corrected, are not the real cause of the crash you experience.
The flush of standard input, fflush(stdin); is something that is not defined by the standard, so using it leads to undefined behavior: in some environments it could work, in some other environment it could not work, and there can be environments (the worst ones) in which it seems to work but it is actually harmful. It is recommended to avoid it.
Function gets() is dangerous because it doesn't provide any control on the size of the string inserted by the user, and its use should be avoided.
The issues in the void addBook() function
You try increasing the available space using realloc:
void *realloc(void *ptr, size_t size);
It needs the original pointer and the new size. But you pass library.books_count that is just the number of books. Meaning that, if the library used to contain 4 books, you try to allocate 5 bytes only.
You instead need to allocate library.books_count * sizeof(Sbook) bytes.
Furthermore it returns a new pointer. You need to assign it to the book pointer:
library.bookp = realloc(library.bookp, library.books_count * sizeof(Sbook));
In main() you initialize a i variable, but you never update it, since you store the numbers of books directly in library.books_count.
Then you pass it to addexistingBooks(), and it is redundant because you could use library.books_count itself for the loop, as you actually do. You can use it as the loop variable, but you don't need to have that parameter. Just
void addexistingBooks(Slib library, )
{
int i; /* If your C version is C99 or later, you can declare it in the loop itself */
for(i=0;i<library.books_count;i++)
{
/* Omissis */
}
}
Finally you pass it to addBook(), and not only it is redundant (as you can simply store the new book at index library.books_count-1, but it is actively harmful because you are always updating index 0 (because the value of parameter i is 0).
Although it is possible to pass structures to functions as values, it is not recommended. The first reason is that you will overload the stack of the process (the whole struct will be allocated in the stack area, that is quite big in PC applications but quite limited in embedded systems). The second reason will give you functional problems.
In fact, parameters passed by value are copies of the variables passed to the function. This means that any change made on them will not be reflected to original structures. In your case, the update of library.bookp pointer will not be available outside the function, causing (1) the original structure pointing to an invalid memory address location (becoming a dangling pointer), (2) the leak of the newly allocated memory, that nobody will be able to free().
Pass structures by address, instead, using pointers to structures. addBook() function, considering the i parameter removal, would become as follows
void addBook(Slib *library)
{
int i = library->books_count;
(library->books_count)++;
library->bookp = realloc(library->bookp, library->books_count * sizeof(Sbook));
/* and so on... the value of 'i' is now library->books_count-1 */
}
/* Call from main */
int main()
{
Slib library;
/* Omissis */
menu(Choice);
if(strcmp(Choice,"add")==0)
{
addBook(&library, i);
}
free(library.bookp);
return 0;
}
The definition of realloc function,
void *realloc(void *ptr, size_t size);
So, your realloc function:
realloc(library.bookp,library.books_count);
should change to:
library.bookp = realloc(library.bookp,sizeof(Sbook)*library.books_count);
OT, i see in your menu function, you use gets. It's dangerous, you should use fgets from stdin in stead. See in this link Why is the gets function so dangerous that it should not be used?
I created a simple C program to display about a simple bank transaction on withdrawals and deposits. I created the variables using structure. But there is a problem in passing structure variables within functions as they are not passing the values from one function to another as well as to main function.
#include <stdio.h>
#include <stdlib.h>
typedef struct Details{
char name[100];
char day[100];
int openingbalance;
int amount;
int closingbalance;
}detail;
void InputDetails(detail customer){
printf("Enter Customer name: ");
scanf("%s",customer.name);
printf("Enter the date: ");
scanf("%s",customer.day);
printf("Enter opening balance: ");
scanf("%d",&customer.openingbalance);
}
void transaction(detail customerr, int money){
int selection;
printf("Opening balance = %d\n",customerr.openingbalance);
printf("Select the transaction\n1.Withdrawal\n2.Deposit\n");
scanf("%d",&selection);
switch(selection){
case 1:
if(money > customerr.openingbalance){
printf("No sufficient balance in the account to process the request\n");
customerr.closingbalance = customerr.openingbalance;
}
else
customerr.closingbalance = customerr.openingbalance - money;
break;
case 2:
customerr.closingbalance = customerr.openingbalance + money;
}
}
void main()
{
detail client;
int amount;
InputDetails(client);
printf("Enter the transaction amount: ");
scanf("%d",&amount);
transaction(client, amount);
FILE *file1;
file1 = fopen("Bank.txt","a+");
printf("Name\tDate\tOpening Balance\tAmount Processed\tClosing Balance\n");
printf("%s \t%s \t%d \t%d \t%d\n",client.name,client.day,client.openingbalance,amount,client.closingbalance);
fprintf(file1,"%s \t%s \t%d \t%d \t%d\n",client.name,client.day,client.openingbalance,amount,client.closingbalance);
fclose(file1);
}
In the output it displays a wrong amount rather the entered opening balance and all the other variables including name and date.
You're passing the struct by value, which creates a copy of it. Operations on the struct in the function don't affect the original variables.
Instead of doing that, you may want to pass a pointer to the variable to your functions.
To do that, you need to change your function signatures to use a pointer to detail:
void InputDetails(detail *customer)
void transaction(detail *customerr, int money)
Since you're using a pointer, you need to dereference it to access the actual data pointed to by the pointer.
For other variable types you'd use the * indirection unary operator to access the value, which you can also do with structs:
(*customerr).closingbalance = (*customerr).openingbalance - money;
This is ugly. Instead of having to do this, you can use the -> operator, which is just a prettier way of doing the above:
customerr->closingbalance = customerr->openingbalance - money;
In your functions, you'd need to replace every use of the . operator on customerr with ->.
Doing this will save both time and memory since you don't have to make a local copy of the struct, and your program can function correctly.
When you call your functions, you'd use the & unary operator to take obtain the address of the struct variable and pass that, instead of the entire struct itself:
InputDetails(&client);
transaction(&client, amount);
You have to pass an object of a structure by reference through using a pointer to the object if you want that the original object would be changed in the function.
For example the function InputDetails should be defined like
void InputDetails(detail *customer){
printf("Enter Customer name: ");
scanf("%s",customer->name);
printf("Enter the date: ");
scanf("%s",customer->day);
printf("Enter opening balance: ");
scanf("%d",&customer->openingbalance);
}
and called like
InputDetails(&client);
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);
}