I have this struct:
typedef struct {
char name[31];
int played;
int won;
int lost;
int tie;
int points;
} Player;
And this function which fill the struct array with data from file:
int load(Player *players[], int max_players, int *player_count)
{
static const char filename[] = "players.txt";
FILE *file = fopen(filename, "r");
if (file != NULL)
{
char line[128];
players = malloc(max_players * sizeof *players);
while (1) /* read until end of file */
{
players[*player_count] = malloc(sizeof(Player));
if (*player_count < max_players && fgets(players[*player_count]->name, sizeof players[*player_count]->name, file) != NULL)
{
fscanf(file, "%d", &players[*player_count]->played); // read played
fscanf(file, "%d", &players[*player_count]->won); // read won
fscanf(file, "%d", &players[*player_count]->lost); // read lost
fscanf(file, "%d", &players[*player_count]->tie); // read tie
fscanf(file, "%d", &players[*player_count]->points); // read points
fgets(line, sizeof line, file); // read new line
// increase player count
*player_count += 1;
}
else
{
break;
}
}
fclose(file);
}
else
{
return 0;
}
return 1;
}
Now I am having a problem with calling it by passing players as a reference so that the updated data of players gets reflected at the calling end.
Below is my calling code, which I think has the problem:
Player *players[MAX_PLAYERS] = { NULL };
int playerCount = 0;
load(players, MAX_PLAYERS, &playerCount);
When I debug the code, the players' array gets filled in the function but when it returns back, the players' value is still null.
Any help would be appreciated.
You are overwriting the local variable players
.
Remove the below line from the function you don't need it.
players = malloc(max_players * sizeof *players);|
As you already have the array of pointers in main
.
You don't need array of pointers of type Player
you just need array of type Player
Player *players;
load(&players, MAX_PLAYERS, &playerCount);
And in load
function.
int load(Player **players, int max_players, int *player_count)
{
static const char filename[] = "players.txt";
FILE *file = fopen(filename, "r");
if (file != NULL)
{
char line[128];
(*players) = malloc(max_players * sizeof **players);
while (1) /* read until end of file */
{
if (*player_count < max_players && fgets((*players)[*player_count].name, sizeof (*players)[*player_count].name, file) != NULL)
{
fscanf(file, "%d", &(*players)[*player_count].played); // read played
fscanf(file, "%d", &(*players)[*player_count].won); // read won
fscanf(file, "%d", &(*players)[*player_count].lost); // read lost
fscanf(file, "%d", &(*players)[*player_count].tie); // read tie
fscanf(file, "%d", &(*players)[*player_count].points); // read points
fgets(line, sizeof line, file); // read new line
// increase player count
*player_count += 1;
}
else
{
break;
}
}
fclose(file);
}
else
{
return 0;
}
return 1;
}
C does not support passing a variable by reference.
I just kept it simple. Your function should look like this:
int load(Player *players, int max_players, int *player_count)
{
static const char filename[] = "players.txt";
FILE *file = fopen(filename, "r");
if (file != NULL)
{
char line[128];
while (!feof(file ) && !ferror(file )) /* read until end of file */
{
fscanf(file, "%d", &players[*player_count].played); // read played
fscanf(file, "%d", &players[*player_count].won); // read won
fscanf(file, "%d", &players[*player_count].lost); // read lost
fscanf(file, "%d", &players[*player_count].tie); // read tie
fscanf(file, "%d", &players[*player_count].points); // read points
fgets(line, sizeof line, file); // read new line
// increase player count
*player_count += 1;
}
fclose(file);
return 1;
}
return 0;
}
and main:
int main ()
{
Player players[MAX_PLAYERS] = { NULL };
int playerCount = 0;
load(players, MAX_PLAYERS, &playerCount);
printf("");
}
the following proposed code:
main()
main()
stderr
all the error information, then exits main()
to pass all the allocated memory pointers to free()
to avoid a memory leak and now, the proposed code modifications:
regarding:
typedef struct
{
char name[31];
int played;
int won;
int lost;
int tie;
int points;
} Player;
this anonymous struct will be very difficult to display
the individual fields via a debugger,
because debuggers use the 'tag' name of the struct
to reference the individual fields
in main function: Notice only declaring a pointer initialized to NULL,
then passing the address of the pointer to the function: `load()`
Player *players = NULL;
int playerCount = 0;
load(&players, &playerCount);
notice the double '**' on the 'players' parameter
This enables the sub function to modify the pointer field in the caller
int load(Player **players, int *player_count)
{
static const char filename[] = "players.txt";
// it is poor programming practice to name a variable the
// same as a struct, so changed `file` to `fp`
FILE *fp = fopen(filename, "r");
if( !fp )
{
perror( "fopen to read players.txt failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
// increased the size of the input buffer `line[]` for safety
char line[1024];
// note: used `calloc()` so when cleaning up from error
// no need to check if a specific entry in the 'player'
// array is used. `free()` handles a NULL parameter just fine
*players = calloc( MAX_PLAYERS, sizeof(Player*) );
if( !*players )
{
perror( "calloc for array of pointers to players failed" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
/* read until end of file or array full*/
while (*player_count < MAX_PLAYERS && fgets(line, sizeof line, fp))
{
(*players)[*player_count] = malloc(sizeof(Player));
if( !(*players)[ *player_count ] )
{
perror( "malloc for individual player failed" );
for( int i=0; i<MAX_PLAYERS; i++ )
{
free( (*players)[i] );
}
free( *players );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
if( sscanf( line, "%d %d %d %d %d",
players[*player_count]->played, // read played
players[*player_count]->won, // read won
players[*player_count]->lost, // read lost
players[*player_count]->tie, // read tie
players[*player_count]->points) != 5 ) // read points
{
fprintf( stderr, "extraction of player fields failed\n" );
exit( EXIT_FAILURE );
}
// increase player count
(*player_count) += 1;
}
fclose(file);
return 0;
}
int func(int ***players){
*players=new int* [MAXSIZE];
//use this if use c
// *players=(int**)malloc(sizeof(int*)*MAXSIZE);
for(int i=0;i<MAXSIZE;i++){
*(*players+i)=new int[2];
// *(*players+i)=(int*)malloc(sizeof(int)*2);
//2 is test can choose every number if your computer allow
}
}
and you main should like this main:
int main(){
int **players=nullptr;
func(&players);
//use follow if you must delete
for(int i=0;i<MAXSIZE;i++){
delete players[i];
}
delete players;
return 0;
}
typedef struct { int played;} Player;
void load(Player* &players, int max_players, int &player_count)
{
players = (Player*)malloc(max_players * sizeof(Player));
for (int i = 0; i < max_players; i++)
{
players[i].played = i;
player_count++;
}
}
int main()
{
const int MAX_PLAYERS=3;
Player* players= NULL ;
int playerCount = NULL;
load(players, MAX_PLAYERS, playerCount);
//...
free(players);
}
typedef struct Foo {
int x;
} Foo;
function:
void f(Foo **foo) {
foo[0]->x = 2021; // already allocate in main
foo[1] = malloc(sizeof(Foo)); // not locate yet
foo[1]->x = 2022;
}
int main() {
Foo **foo = malloc(100 * sizeof(Foo *)); // foo[10]
foo[0] = malloc(sizeof(Foo)); // must allocate before using
foo[0]->x = 2020; // assing 2021 to foo[0].x must use arrow for pointer
f(foo);
foo[1]->x = 2024; // already allocate in function f();
printf("main: value of x: %d\n", foo[0]->x);
printf("main: value of x: %d\n", foo[1]->x);
}
$ gcc test.c && ./a.out
value of x: 2021
value of x: 2024
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.