I'm trying to work on a project where I'm forbidden from using global variables. In my project, I have the following function:
int addAccount()
{
int ID_number = 0;
int ID;
int ID_array[10];
double account_balance;
double balance_array[10];
int choice = getChoice ();
if (choice == 1)
{
if (ID_number + 1 > 10)
{
printf("Error\n");
}
else
{
ID_number = ID_number + 1;
printf("Please enter the id\n");
scanf("%d", &ID);
ID_array[ID_number - 1] = ID;
printf("Please enter the starting balance\n");
scanf("%lf", &account_balance);
balance_array[ID_number - 1] = account_balance;
}
}
return;
I need to somehow get the values for several of these variables and use them in another function (particularly ID, ID_number, and account_balance). The function that I need these values for is as follows:
void displayAccounts ()
{
int count;
int choice = getChoice ();
int ID_number = ID_number ();
if (choice == 2)
{
for (count = 0; count < ID_number; count++)
{
printf("Account #%d: ID is %d\n", count + 1, ID_array[count]);
printf("Account balance is %.2lf\n", balance_array[count]);
}
}
}
I know how to return one value, but I don't know how to make multiple values usable outside of the function where they occur. Is what I'm trying to do even possible or is it likely that I'm going about my project the wrong way?
Use a struct:
struct Account
{
int count;
int ID_number;
int balance_array[10];
// etc etc
};
Pass a pointer to addAccount:
void addAccount(struct Account *account)
{
account->ID_number = 0;
// etc
}
And then pass it to displayAccounts
void displayAccount(struct Account *account)
{
}
Eg:
struct Account account;
addAccount(&account);
displayAccount(&account);
Note that in C you need to use the struct prefix unless you typedef the struct.
The most obvious choice is to create a struct, which can have any number of fields (including arrays), and which can be both passed to and returned from a function. In that way you can pass around the necessary state.
You can of course also optimize it a bit by having a root function define the struct variable, and then just pass around pointers to the same instance.
You can use a structure to send the values.
Also the pointers can be a good alternate to return multiple values in C.
You can Refer to The following links too:
http://www.stackoverflow.com/questions/2620146/how-do-i-return-multiple-values-from-a-function-in-c
http://www.c4learn.com/c-programs/return-multiple-values-from-function.html
Related
I'm working on the last exercise of the "Think like a computer scientist, C version" book and I have some trouble with one particular point.
The exercise consists of making a small game, where the computer picks a random value between 0 and 20 and then asks me to guess the number.
After that, the computer counts the number of tries I made and, if I get a better score than the previous party, I need to store my name and the number of tries in a structure.
My problem is the following: When I restart the game, the string value, player_name, in the structure gets somehow deleted but player_score is still there.
First, I made a "call by value" function to create the structure and then a tried with a "call by reference" but getting the same results.
I think I tried everything I could with my actual knowledge for now; so, if someone could check my code and give me some tips about what's wrong I would much appreciate it!
//HEADERS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FALSE 0
#define TRUE 1
//TYPEDEF STRUCTS
typedef struct
{
int player_score;
char *player_name;
} HS_Player;
//FUNCTION PROTOTYPES
int Random_Value(void);
int Get_User_Choice(void);
int Check_Result(int computer, int my_choice);
int Try_Again(int game_result, int computer);
void Player_Infos(HS_Player *player_p, int score);
int Game_Restart(void);
//MAIN
int main(void)
{
int end_game;
int high_score_value = 100;
HS_Player player;
while (end_game != TRUE)
{
int computer_number = Random_Value();
printf("Guess the number between 0 et 20 chosen by the computer.\n");
int your_number = Get_User_Choice();
int result_game = Check_Result(computer_number, your_number);
int tries_to_win = Try_Again(result_game, computer_number);
printf("Number of tries: %i\n", tries_to_win);
if (tries_to_win < high_score_value)
{
Player_Infos(&player, tries_to_win );
high_score_value = player.player_score;
}
printf("Highest score: %i By: %s\n", player.player_score, player.player_name);
printf("\n");
end_game = Game_Restart();
}
return EXIT_SUCCESS;
}
//Random_Value FUNCTION
int Random_Value(void)
{
srand(time(NULL));
int x = rand();
int y = x % 20;
return y;
}
//Get_User_Choice FUNCTION
int Get_User_Choice(void)
{
int success, x;
char ch;
printf("Your Guess:\t");
success = scanf("%i", &x);
while (success != 1)
{
printf("Your input is not a number. Please try again:\t");
while ((ch = getchar()) != '\n' && ch != EOF);
success = scanf("%i", &x);
}
if (x < 0 || x > 20)
{
printf("Your input must be between 0 and 20. Please try again.\n");
Get_User_Choice();
}
return x;
}
//Check_Result FUNCTION
int Check_Result(int computer, int my_choice)
{
int check_result;
if (my_choice < computer)
{
printf("Computer number is larger!\n");
check_result = FALSE;
}
else if (my_choice > computer)
{
printf("Computer number is smaller!\n");
check_result = FALSE;
}
else if (my_choice == computer)
{
printf("It's a Match! You chose the same number than the computer.\n");
printf("\n");
check_result = TRUE;
}
return check_result;
}
//Try_Again FUNCTION
int Try_Again(int game_result, int computer)
{
int tries_befor_success = 1;
while (game_result != TRUE)
{
int your_number = Get_User_Choice();
game_result = Check_Result(computer, your_number);
tries_befor_success++;
}
return tries_befor_success;
}
//Player_Infos FUNCTION
void Player_Infos(HS_Player *player_p, int score)
{
char new_name[80];
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
scanf("%s", new_name);
printf("\n");
player_p->player_score = score;
player_p->player_name = new_name;
}
//Game_Restart FUNCTION
int Game_Restart(void)
{
int quit_value;
printf("Quit Game ?\n");
printf("Press 'y' to quit or any other keys to continue.\n");
fflush(stdin);
char quit_game = getchar();
printf("\n");
if (quit_game == 'y')
{
quit_value = TRUE;
}
else
{
quit_value = FALSE;
}
return quit_value;
}
The problem is that, in your Player_Infos function, you are assigning the address of a local array to the char* player_name pointer member of the passed structure. When that function ends, the local array it used will be deleted and the pointer in the structure will be invalid. (In the case of the player_score, you don't have that problem, because the given value is copied to the structure member.)
There are several ways around this; one would be to use the strdup() function to make a copy of the local char new_name[80]; array – but that is really overkill, and you would need to manage (i.e. free()) that allocated string whenever you make a modification.
A simpler way is to make the player_name member an actual array of char and then use strcpy() to copy the local array into that member.
Better, still, with the player_name member defined as char [80], you can read directly into that (in the function), and avoid the local array completely:
typedef struct
{
int player_score;
char player_name[80];
} HS_Player;
//...
void Player_Infos(HS_Player *player_p, int score)
{
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
// Read directly. Limit input to 79 chars (allowing room for null terminator).
scanf("%79s", player_p->player_name);
printf("\n");
player_p->player_score = score;
}
Also, just as a "style" tip, you may want to change the member names to just score and name, as the "player" part is implied by the structure type-name itself.
This issue you are having is that you are associating the player name pointer to a variable that goes out of scope when you leave the "player_Infos" function. What you probably would want to do is define the name as a character array in your structure and then use the "strcpy" call in your function instead. Following is a couple of code snippets illustrating that point.
//TYPEDEF STRUCTS
typedef struct
{
int player_score;
char player_name[80];
} HS_Player;
Then, in your function, use the "strcpy" call.
//Player_Infos FUNCTION
void Player_Infos(HS_Player *player_p, int score)
{
char new_name[80];
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
scanf("%s", new_name);
printf("\n");
player_p->player_score = score;
strcpy(player_p->player_name, new_name);
//player_p->player_name = new_name;
}
When I tested that out, I got a name to appear in the terminal output.
Computer number is smaller!
Your Guess: 4
It's a Match! You chose the same number than the computer.
Number of tries: 8
Highest score: 4 By: Craig
FYI, you will need to include the "string.h" file.
Give that a try.
Name Update
The reason your player.player_name is not getting updated is because you can't assign a string this way in C. When doing player_p->player_name = new_name; you're actually saving in player_p->player_name the memory address of new_name.
Instead, what you want to achieve, is to copy each character of new_name to player_p->player_name and in order to achieve this, you have to change the type of prlayer_name field from char* player_name to char player_name[80], then assign it using, for example, strcpy():
#include <string.h>
// [...]
//TYPEDEF STRUCTS
typedef struct
{
unsigned int player_score;
char player_name[80];
} HS_Player;
// [...]
//Player_Infos FUNCTION
void Player_Infos(HS_Player *player_p, int score)
{
char new_name[80];
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
scanf("%s", new_name);
printf("\n");
player_p->player_score = score;
strcpy(player_p->player_name, new_name);
}
Data Persistence
To make data (players info) persistent over multiple runs, you have to save the content of the struct to a file.
Example
int Save_Score(char* filename, HS_Player* player)
{
FILE* file = fopen(filename, "w");
if (file == NULL)
{
fprintf(stderr, "\nAn error occurred while opening the file\n");
return -1;
}
if (fprintf(file, "%d %s", player->player_score, player->player_name) < 0)
return -1;
fclose(file);
return 0;
}
int Load_Score(char* filename, HS_Player* player)
{
FILE* file = fopen(filename, "r");
if (file == NULL)
{
fprintf(stderr, "\nAn error occurred while opening the file\n");
return -1;
}
if (fscanf(file, "%d %79s", &player->player_score, player->player_name) < 0)
return -1;
fclose(file);
return 0;
}
I have a certain program that lets you register members and save their name and birthdate into arrays. The particular function that does this registration uses the following code;
char regmember (struct member a[])
{
int i = 0;
char wow;
do
{
//registration
printf("\n Do you want to add someone else (y/n):");
scanf(" %c",&wow);
i++
}while(wow != 'n');
int nrofmembers = i;
return nrofmembers;
}
-> I save the user input by using
scanf("%s",a[i].name) and scanf("%d",&a[i].ID);
which is why I am using i++. As you realize, the int variable i, will hold the number of members who have been registered. I want to utilize this info in order to use it in loops in other functions, so I went on to save the value of i in another int variable...
int nrofmembers = i;
My problem is, I can't use that variable (nrofmembers) else where, even though I tried returning it, any advice?
you need both to get i in parameter and to return the new value, you can do
int regmember (struct member a[], int i)
{
... use and modify i
return i;
}
or using it as an input-output variable
void regmember (struct member a[], int * i)
{
... use and modify *i
}
In the first case the caller do for instance :
int i = 0;
for (...) {
...
i = regmember(..., i);
...
}
and in the second case :
int i = 0;
for (...) {
...
regmember(..., &i);
...
}
Suppose you keep the members in a global array, then you can manage how many members are in your array also as a global variable, for example
struct member gMembers[MAX_MEMBERS];
int gnMembers;
Your function can now operate on this array directly:
int regmember (void)
{
if (gnMembers < MAX_MEMBERS)
{
// add member
if (scanf("%s",gMembers[gnMembers].name)==1
&& scanf("%d",&gMembers[gnMembers].ID)==1) {
gnMembers++;
return 1; // success
}
}
return 0; // array full or scanf error
}
I am currently trying to store information that is input from a function to a struct declared in my header file and utilize it within the main file. I cannot use struct arrays because I am not allowed to allocate memory.
header file
#ifndef HOMEWORK_H_
#define HOMEWORK_H_
typedef struct
{
int CourseID[25];
char CourseName[100][25];
}Course;
void NewCourse(void);
#endif
My code
#include <stdio.h>
#include <stdlib.h>
#include "Homework.h"
void NewCourse()
{
int i;
int CNumber = 0;
Course storeC;
for(i = 0; i < 0; i++)
{
if(storeC.CourseID[i] == 0)
{
if(storeC.CourseName[i] == NULL)
{
int CNumber = i;
break;
}
}
}
printf("%d\n", CNumber);
printf("Please enter the course's ID number: ");
scanf("%d", &storeC.CourseID[CNumber]);
printf("Please enter the course's name: ");
scanf("%s", storeC.CourseName[CNumber]);
}
and my main does not really apply since the problem lies within storing the data.
A few things to keep in mind is I must utilize a separate file for my functions and I must use a header file for my structs.
I know my for loop to determine where in the array may not be effective, but I am not so worried about it as of right now.
My question is how do I store the data from this function to the
header file?
Update
I changed the main function to fit everything else and I end up with this error now.
a label can only be part of a statement and a declaration is not a
statement
The code in main is:
switch(Option)
{
case 1:
Course c = NewCourse();
printf("%d\n%s\n", c.CourseID[0], c.CourseName[0]); // For testing purposes
break;
What is causing the error because it says it stems from line 29 which is the Course c = NewCourse();?
Change NewCourse to return a Course.
Course NewCourse(void);
Change the implementation to:
Course NewCourse()
{
int i;
int CNumber = 0;
Course storeC;
...
return storeC;
}
Change main accordingly.
int main()
{
Course c = NewCourse();
}
PS
You said,
I cannot use struct arrays because I am not allowed to allocate memory.
I assume that to mean that you cannot use dynamic memory allocation. If you are allowed to create an array of structs in the stack, you can simplify your code by using:
typedef struct
{
int CourseID[25];
char CourseName[100];
}Course;
void NewCourse(Course course[]);
and in main, use:
Course courses[25];
NewCourse(courses)
In response to your update
You needed to add a scope block { } around the code as follows:
int main()
{
{
Course c = NewCourse();
}
}
This should resolve your error and allow your code to compile.
Additionally, you have an error in manipulating the CNumber Variable. It is declared twice, with different scopes:
int CNumber = 0; // the first definition with the scope of the NewCourse Function
Then inside the test, with a block scope:
if(storeC.CourseID[i] == 0)
{
if(storeC.CourseName[i] == NULL)
{
int CNumber = i; // block-scope. This is not the same CNumber Variable (todo: Omit int)
break;
}
}
As a result, when you reference it later in
printf("%d\n", CNumber);
printf("Please enter the course's ID number: ");
scanf("%d", &storeC.CourseID[CNumber]);
printf("Please enter the course's name: ");
scanf("%s", storeC.CourseName[CNumber]);
It will be always reference the function scope variable, which is always be zero.
Solution: omit the int declaration inside the test:
if(storeC.CourseName[i] == NULL)
{
CNumber = i;
break;
}
I have a struct person that has the following elements, defined in data.h
typedef struct person{
char firstName[20];
char familyName[20];
char telephoneNum[20];
int type; // 0 = student / 1 = employee;
}newPerson;
I created an array of person[MAX_PERSONS] that is initialized in my menu() function. I then have an addFirstName(newPerson pers) function. However when I try to test print format using my printFormat(newPerson pers)function, I get blank, instead of the inputted name.
I have included the menu(), addFirstname(newPerson pers), and printFormat(newPerson pers) function below. I was wondering if anyone could tell me the reason for this. Any help or pointers would be appreciated. Thank you in advance.
int menu(){
int num = 0;
newPerson person[MAX_PERSONS];
int option; // for user input for menu
printf("\n\tPlease choose one of the following options to continue (0-9): ");
scanf("%d", &option );
printf("\n\tYou selected %d\n", option);
if (option == 0){ //program will close
printf("\tProgram will now close.\n");
exit(1);
}
if (option == 1){ //program will ask for name input
addRecord(person[num]);
printFormat(person[num]);
char choice[0];
printf("\n\t\tWould you like to enter another record? (y/n): ");
scanf("%s", choice);
if (choice[0] == 'y'){
num++;
addRecord(person[num]);
}
if (choice[0] == 'n'){
num++;
mainMenu();
}
/*
IF YES, THEN NUM++
THEN RUN ADDRECORD(PERSONNUM) AGAIN.
IF NO, THEN RETURN TO MAIN MENU.
PRINTMENU
THEN RUN MENU AGAIN
*/
}
printf("\n\tNot a valid option, please try again // THE END OF MENU FUNCTION\n");
return 0;
}
void addFirstName(newPerson pers){
char firstName[20];
printf("\n\tEnter first Name: ");
scanf("%20s", firstName);
strcpy(pers.firstName, firstName);
printf("\n\tThe name entered is %s", pers.firstName);
}
void printFormat(newPerson pers){
printf("\t\tThe name is %s", pers.firstName);
}
It's because you pass the structure to addFirstName by value meaning that the function receives a copy of the structure. And changing a copy will of course not change the original.
While C does not support passing arguments by reference, it can be emulated using pointers. So change the addFirstName function to receive a pointer to the structure as its argument.
Your big problem is that you are passing structures by value instead of by pointers. This result in that you change copies of original objects inside your function addFirstName and not the original object. You should declare it as:
void addFirstName( newPerson* pers);
void printFormat( newPerson* pers);
Example:
#include <stdio.h>
void call_by_value(int x) {
printf("Inside call_by_value x = %d before adding 10.\n", x);
x += 10;
printf("Inside call_by_value x = %d after adding 10.\n", x);
}
int main() {
int a=10;
printf("a = %d before function call_by_value.\n", a);
call_by_value(a);
printf("a = %d after function call_by_value.\n", a);
return 0;
}
this will produce:
a = 10 before function call_by_value.
Inside call_by_value x = 10 before adding 10.
Inside call_by_value x = 20 after adding 10.
a = 10 after function call_by_value.
I am new to C and very much interested in knowing how to approach any problem which has more than 3 or 4 functions, I always look at the output required and manipulate my code calling functions inside other functions and getting the required output.
Below is my logic for finding a students record through his Id first & then Username.
This code according to my professor has an excessive logic and is lacking in many ways, if someone could assist me in how should I approach any problem in C or in any other language it would be of great help for me as a beginner and yes I do write pseudo code first.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int id; //Assuming student id to be unique
int age;
char *userName; //Assuming student userName to be unique
char *dept;
}student; // Alias "student" created for struct
student* createstruct(); // All function prototype declared
student* createArray();
void addstruct(student* s2);
void searchChar(student* s2,int num);
void searchInt(student* s2,int num);
student* createstruct() // function createStruct() to malloc data of struct student.
{
student *s;
s = (student*)malloc(sizeof(student));
s->userName = (char*)malloc(sizeof(char)*32);
s->dept = (char*)malloc(sizeof(char)*32);
printf("please enter id ");
scanf("%d",&s->id);
printf("please enter age ");
scanf("%d",&s->age);
printf("please enter userName ");
scanf("%31s",s->userName);
printf("please enter department ");
scanf("%31s",s->dept);
printf("\n");
return s;
}
student* createArray()
{
student *arr; //declaration of arr poiter, type struct student
arr = (student*)malloc(sizeof(student)*10); // memory allocated for a size of 10
return arr;
}
void addstruct(student *s2) // function for adding data to the structures in array
{
int i,num;
student* s1;
printf("please enter the number of records to add:");
scanf("%d",&num);
printf("\n");
if(num>0 && num<11)
{
for(i=0;i<num;i++) // if user want to enter 5 records loop will only run 5 times
{
s1 = createstruct();
s2[i].id = s1->id; // traversing each element of array and filling in struct data
s2[i].age = s1->age;
s2[i].userName = s1->userName;
s2[i].dept= s1->dept;
}
}
else if(num>10) // if user enters more than 10
{
for(i=0;i<10;i++) // loop will still run only 10 times
{
s1 = createstruct();
s2[i].id = s1->id;
s2[i].age = s1->age;
s2[i].userName = s1->userName;
s2[i].dept = s1->dept;
}
printf("Array is full"); // Array is full after taking 10 records
printf("\n");
}
searchInt(s2,num); // Calling searchInt() function to search for an integer in records
searchChar(s2,num); // Calling searchChar() function to search for a string in records
free(s1);
free(s2);
}
void searchChar(student* s2,int num) // function for searching a string in records of structure
{
char *c;
int i;
c = (char*)malloc(sizeof(char)*32);
printf("please enter userName to search ");
scanf("%31s",c);
printf("\n");
for (i=0;i<num;i++) //num is the number of struct records entered by user
{
if ((strcmp(s2[i].userName,c)==0)) //using strcmp for comparing strings
{
printf("struct variables are %d, %d, %s, %s\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in userName matches: <%s>\n",c);
break;
}
}
}
void searchInt(student* s2,int num) //searchs for an integer and prints the entire structure
{
int i,z;
printf("please enter id to search ");
scanf("%d",&z);
printf("\n");
for (i=0;i<num;i++)
{
if (s2[i].id == z)
{
printf("struct variables are %d, %d, %s, %s\n\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in id matches: <%d>\n\n",z);
break;
}
}
}
int main(void)
{
student *s2;
s2 = createArray();
addstruct(s2);
return 0;
}
I'm not going to go into optimizing, because if you wanted better theoretical performance you would probably go with different data structures, such as ordered arrays/lists, trees, hash tables or some kind of indexing... None of that is relevant in this case, because you have a simple program dealing with a small amount of data.
But I am going to tell you about the "excessive logic" your professor mentioned, taking your searchInt function as an example:
for (i=0;i<num;i++)
{
if (s2[i].id == z)
{
printf("struct variables are %d, %d, %s, %s\n\n", s2[i].id,s2[i].age,s2[i].userName,s2[i].dept);
break;
}
else if(i == num-1)
{
printf("nothing in id matches: <%d>\n\n",z);
break;
}
}
The thing here is that every time around the loop you're testing to see if you're at the last element in the loop. But the loop already does that. So you're doing it twice, and to make it worse, you're doing a subtraction (which may or may not be optimized into a register by the compiler).
What you would normally do is something like this:
int i;
student *s = NULL;
for( i = 0; i < num; i++ )
{
if( s2[i].id == z ) {
s = &s2[i];
break;
}
}
if( s != NULL ) {
printf( "struct variables are %d, %d, %s, %s\n\n",
s->id, s->age, s->userName, s->dept );
} else {
printf("nothing in id matches: <%d>\n\n",z);
}
See that you only need to have some way of knowing that the loop found something. You wait for the loop to finish before you test whether it found something.
In this case I used a pointer to indicate success, because I could then use the pointer to access the relevant record without having to index back into the array and clutter the code. You won't always use pointers.
Sometimes you set a flag, sometimes you store the array index, sometimes you just return from the function (and if the loop falls through you know it didn't find anything).
Programming is about making sensible choices for the problem you are solving. Only optimize when you need to, don't over-complicate a problem, and always try to write code that is easy to read/understand.