• 0

[C] Change values of a struct within a function


Question

Hey guys, the snippet of code below is the definition of a struct called "Game" as well as a function that has been initialised, called "Game throwdice" for my uni project. I have two questions what does the struct function type do? Also I want to be able to update the values in the struct from within the function. I am not allowed to change the definition of the Game throwdice function to use pointers. How would I go about changing the values of the struct? My attempt at making this work is in the second code snippet:


// advance the game to the next turn,
typedef struct _game {
int diceScore;
int currentTurn;
} Game;
// assuming that the dice has just been rolled and produced diceScore
// the game starts in turn -1 (we call this state "Terra Nullis") and
// moves to turn 0 as soon as the first dice is thrown.
Game throwDice (Game g, int diceScore);
[/CODE]

My attempt at implementing this function:

[CODE]
Game throwDice (Game g, int diceScore){
g.diceScore=diceScore; //update the diceScore in the struct
g.currentTurn++; //advance the game to the next turn
return g;
}
[/CODE]

18 answers to this question

Recommended Posts

  • 0
  On 29/04/2012 at 04:14, ~Matt~ said:

what does the struct function type do?

I have absolutely no ideal what you intended with this question, therefore I cannot answer it. I assume that you are familiar with both structures and functions in C, and therefore didn't simply use the wrong terminology. If you would clarify, someone may be able to answer you.

  On 29/04/2012 at 04:14, ~Matt~ said:

How would I go about changing the values of the struct?

This question, on the other hand, is much more straight forward. If you are not allowed to change the function interface, I believe that you already have a workable implementation. Are you having any problems with it?

You can verify that your code works using the driver below.


#include <stdio.h>
#include <time.h>

// advance the game to the next turn,
typedef struct _game {
int diceScore;
int currentTurn;
} Game;

// assuming that the dice has just been rolled and produced diceScore
// the game starts in turn -1 (we call this state "Terra Nullis") and
// moves to turn 0 as soon as the first dice is thrown.
Game throwDice (Game g, int diceScore);

// initialize the structure to start the game
Game startGame (void);

Game throwDice (Game g, int diceScore) {
g.diceScore=diceScore; //update the diceScore in the struct
g.currentTurn++; //advance the game to the next turn
return g;
}

Game startGame (void) {
Game g;
g.diceScore=0;
g.currentTurn=-1;
return g;
}

int main (int argc, char * argv[]) {
Game g=startGame();
printf("Game diceScore = %d\nGame currentTurn = %d\n", g.diceScore, g.currentTurn);
srand(time(NULL));
g=throwDice(g, rand()%6+1);
printf("Game diceScore = %d\nGame currentTurn = %d\n", g.diceScore, g.currentTurn);
return 0;
}
[/CODE]

If you were allowed to modify the function prototype, this would be a much better (and more conventional) way to solve the problem:

[CODE]
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// advance the game to the next turn,
typedef struct _game {
int diceScore;
int currentTurn;
} Game;

// assuming that the dice has just been rolled and produced diceScore
// the game starts in turn -1 (we call this state "Terra Nullis") and
// moves to turn 0 as soon as the first dice is thrown.
// returns -1 on failure and 0 on success
int throwDice (Game * g, int diceScore) {
if (!g) return -1;
g->diceScore=diceScore; //update the diceScore in the struct
g->currentTurn++; //advance the game to the next turn
return 0;
}

// Initialize a handle to start the game.
Game * startGame (void) {
Game * g=malloc(sizeof(Game));
g->diceScore=0;
g->currentTurn=-1;
return g;
}

// End the game by destroying its handle.
void endGame (Game * g) {
free( g );
}

int main (int argc, char * argv[]) {
Game * g=startGame();
printf("Game diceScore = %d\nGame currentTurn = %d\n", g->diceScore, g->currentTurn);
srand(time(NULL));
if (throwDice(g, rand()%6+1)<0) {
fprintf(stderr, "The game ended prematurely.\n");
endGame(g);
return -1;
}
printf("Game diceScore = %d\nGame currentTurn = %d\n", g->diceScore, g->currentTurn);
endGame(g);
return 0;
}
[/CODE]

I hope this satisfactorily answers your second question, at least.

  • 0

think of struct as a light weight class and is less expensive.

Unlike classes, structs can be instantiated without using the new. If you do not use new, the fields will remain unassigned and the object cannot be used until all of the fields are initialized. -- I think this was ur problem.

  • 0
  On 29/04/2012 at 05:49, still1 said:

think of struct as a light weight class and is less expensive.

Unlike classes, structs can be instantiated without using the new. If you do not use new, the fields will remain unassigned and the object cannot be used until all of the fields are initialized.

This is C. There are no classes. And even if it wasn't C, I can't think of a language where anything of what you just said would be true. Certainly not C++; in C++ "class" is just an alternate keyword for "struct" and means the exact same thing.
  • 0
  On 29/04/2012 at 04:14, ~Matt~ said:

Hey guys, the snippet of code below is the definition of a struct called "Game" as well as a function that has been initialised, called "Game throwdice" for my uni project. I have two questions what does the struct function type do?

Functions are not "initialized", they are "defined" or "declared". I have no idea what you might mean by "struct function type". The code you posted featured a struct and a function.
  Quote
Also I want to be able to update the values in the struct from within the function. I am not allowed to change the definition of the Game throwdice function to use pointers. How would I go about changing the values of the struct?
You're not allowed to change the definition, but the values of an instance of that type, yes. Think of the type definition as a blueprint for creating instances: it defines what members each instance of "Game" will hold.

It's kind of strange that you ask that question when you do change the values of the struct in the very code you submitted, i.e. in the function throwDice. When you do:

Game g;

g.diceScore = something;

you are changing the value of the member diceScore of the instance "g" of your struct Game. So you seem to already know how to achieve what you want. I'm probably not understanding what your real question is, but it's hard to tell.

  • 0
  On 29/04/2012 at 06:28, Dr_Asik said:

This is C. There are no classes. And even if it wasn't C, I can't think of a language where anything of what you just said would be true. Certainly not C++; in C++ "class" is just an alternate keyword for "struct" and means the exact same thing.

C#

Just trying to help Op and not finding wrong with everything without looking just like what you are doing.

It was my bad thinking that it was c#

  • 0
  On 29/04/2012 at 06:39, Dr_Asik said:

I have no idea what you might mean by "struct function type".

By struct function type, I was just wondering what the difference is/was when declaring a function with

Game throwDice (Game g, int diceScore);[/CODE]

rather than:

[CODE]int throwDice (Game g, int diceScore) ;[/CODE]

It appears that I still do not know what my problem was/is. When I run xorangekiller's implementation of my function it works but when I try write my own the values still don't change:

[CODE]
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct _game {
int diceScore;
int currentTurn;
} Game;
Game throwDice(Game g, int diceScore);
Game throwDice(Game g, int diceScore){
g.currentTurn++;
g.diceScore=diceScore;
return g;
}
int main (int argc, const char * argv[])
{
Game g;
srand((unsigned)time(NULL));
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
throwDice(g,rand()%6+1);
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
return 0;
}
[/CODE]

When I run the code I get this as the output:

[CODE]
0 is the turn AND 0 is the diceScore
0 is the turn AND 0 is the diceScore
[/CODE]

  • 0

Why don't you pass the Game object by a pointer and then modify it?

void throwDice(Game * g, int diceScore)
{
		g-&gt;currentTurn++;
		g-&gt;diceScore=diceScore;
}

and then

Game g;
throwDice(&amp;g, rand()%6+1);

Also make sure you perform some initialisation on g before you pass it to throw dice

Edit:

Also the difference between those functions is the return type. One returns an int, the other returns a Game.

  • 0
  On 29/04/2012 at 07:01, ~Matt~ said:

It appears that I still do not know what my problem was/is. When I run xorangekiller's implementation of my function it works but when I try write my own the values still don't change

You're avoiding using pointers by returning the modified Game object. The Game object you have in main() will never be changed by the function. In main, you need to set g equal to the returned value of throwDice(). That's how your copy will be changed. If you don't save the return value of throwDice() - basically, what you have done - then nothing will happen to g.

Basically, your code:


int main (int argc, const char * argv[])
{
Game g;
srand((unsigned)time(NULL));
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
throwDice(g,rand()%6+1);
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
return 0;
}
[/CODE]

Should be changed to:

[CODE]
int main (int argc, const char * argv[])
{
Game g;
srand((unsigned)time(NULL));
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
g = throwDice(g,rand()%6+1);
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
return 0;
}
[/CODE]

  • 0
  On 29/04/2012 at 07:01, ~Matt~ said:

By struct function type, I was just wondering what the difference is/was when declaring a function with

Game throwDice (Game g, int diceScore);[/CODE]

rather than:

[CODE]int throwDice (Game g, int diceScore) ;[/CODE]

1: If you dont know the diferrence there, I think there are bigger issues at hand.

2: If #1, folks, dont bring pointers into this :p

3: This is a uni project and you dont know #1?

I think there is something OP is not telling us, modifiy, etc

  • 0
  Quote
By struct function type, I was just wondering what the difference is/was when declaring a function with

Game throwDice (Game g, int diceScore);[/CODE]

rather than:

[CODE]int throwDice (Game g, int diceScore) ;[/CODE]

The difference is that the first version returns an int, whereas the second version returns a Game. The first term of a function signature is the return type.
  Quote
It appears that I still do not know what my problem was/is. When I run xorangekiller's implementation of my function it works but when I try write my own the values still don't change:

[CODE]#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct _game {
int diceScore;
int currentTurn;
} Game;
Game throwDice(Game g, int diceScore);
Game throwDice(Game g, int diceScore){
g.currentTurn++;
g.diceScore=diceScore;
return g;
}
int main (int argc, const char * argv[])
{
Game g;
srand((unsigned)time(NULL));
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
throwDice(g,rand()%6+1);
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
return 0;
}[/CODE]

That's a very good question and it's fundamental to understand this in C (and any programming language, really). Let's illustrate with a simple example:

[CODE]
void increment(int number) {
number = number + 1;
}

int main() {
int i = 0;
increment(i);
/* what is the value of i? */
}
[/CODE]

The value of i after the call to increment() is still 0, because the parameter "number" [b]is a copy[/b] of the original. Therefore, the copy is incremented, but the original keeps the same value.

So how can we change values using functions in C?? Simple solution: return the new value and assign it to the original variable. Let's illustrate:

[CODE]
int increment(int number) {
number = number + 1;
return number;
}

int main() {
int i = 0;
i = increment(i);
/* what is the value of i? */
}
[/CODE]

What happens here? A copy of i is passed to function increment under the name "number". number is incremented, and its value is returned. This value is then assigned to i, which is now therefore 1.

Notice that here we are copying the parameter into the function and copying it out again on the return. Copying an integer is very cheap, but for larger structures this gets expensive. This is where pointers come in: a pointer allows you to modify the original value without copying it. Example:

[CODE]
void increment(int* number) {
*number = *number + 1;
}

int main() {
int i = 0;
increment(&i);
/* what is the value of i? */
}
[/CODE]

The value of i after the call is 1, because instead of passing a copy of i, we passed a copy of its address in memory, i.e. a pointer. The function increment then accessed the value at that address and modified it (using the "*" notation). Therefore, the original value is modified without having been copied.

That was a basic presentation, you really should read a good tutorial or book on C to gain a solid understanding of these concepts. It's impossible to write any interesting program if you don't understand values vs pointers.

  On 29/04/2012 at 06:59, still1 said:

C#

Just trying to help Op and not finding wrong with everything without looking just like what you are doing.

It was my bad thinking that it was c#

Sorry for sounding harsh, it was 2AM and I couldn't find sleep. I should stop posting at these hours. Anyway, I thought about C# but even then value types are not really "lightweight" classes, and reference types can also be unassigned - their default value is null rather than 0 or some other value. So I figured the comment was inaccurate regardless of language and that apparently irritated me to no end.
  • 0
  On 29/04/2012 at 07:01, ~Matt~ said:

By struct function type, I was just wondering what the difference is/was when declaring a function with

Game throwDice (Game g, int diceScore);[/CODE]

rather than:

[CODE]int throwDice (Game g, int diceScore) ;[/CODE]

It appears that I still do not know what my problem was/is. When I run xorangekiller's implementation of my function it works but when I try write my own the values still don't change:

Based on your last post, I think that your problem is that you are missing some of the subtleties of C. Like rfirth pointed out above, the reason that my implementation works and yours does not entirely comes down to the fact that I was saving the return value and you were not. Notice the difference between the two code snipets below. The former is your implementation and the latter is mine.

[CODE]
throwDice(g,rand()%6+1);
[/CODE]

[CODE]
g = throwDice(g,rand()%6+1);
[/CODE]

However, like I stated in my earlier post, that is not really a good way to do it. What you are actually doing is creating multiple instances of your structure rather than working with just one and reassigning its variables directly (such as my pointer implementation). Therefore, your confusion as to the reason why the function returning the Game type would work but the one returning an int would not is probably due to a misconception on your part about what C is actually doing when you pass an argument to a function. When you pass g to throwDice() as the first argument, a copy of g is created to be used within throwDice(). Hence, when you change g.currentTurn and g.diceScore within the function, only the local copy is changed. The reason that it works when you return your local instance of g is because you are returning another copy of throwDice()'s local instance of g and setting the original instance of g in main() equal to it.

The function would work the way you most likely assume that it should if you passed g to throwDice() by reference. In that case, you would not have a local copy of g, but would, instead, be directly modifying the values within your instance of g in main(). (NOTE: this is only valid in C++, not in C. In C, you need to use pointers (as in my earlier post) to accomplish the same thing.) The driver below demonstrates pass by reference (in C++, there is no such concept in C).

[CODE]
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// advance the game to the next turn,
typedef struct _game {
int diceScore;
int currentTurn;
} Game;

// assuming that the dice has just been rolled and produced diceScore
// the game starts in turn -1 (we call this state "Terra Nullis") and
// moves to turn 0 as soon as the first dice is thrown.
// returns -1 on failure and 0 on success
int throwDice (Game &g, int diceScore);

// initialize the structure to start the game
void startGame (Game &g);

int throwDice (Game &g, int diceScore) {
if (diceScore<1 || diceScore>6) return -1;
g.diceScore=diceScore; // update the diceScore in the struct
g.currentTurn++; // advance the game to the next turn
return 0;
}

void startGame (Game &g) {
g.diceScore=0;
g.currentTurn=-1;
}

int main (int argc, char * argv[]) {
Game g;
startGame(g);
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
srand(time (NULL));
if (throwDice(g, rand()%6+1)<0) {
fprintf(stderr, "The game ended prematurely.\n");
return -1;
}
printf("%d is the turn AND %d is the diceScore\n",g.currentTurn, g.diceScore);
return 0;
}
[/CODE]

Edit: Ah! Dr_Asik beat me to it (and has a more thorough explanation). I concede defeat.

  • 0

Thanks for your time guys :)

Appreciated! I understand now. But for this task I am not allowed to change the declaration of the functions, so I cannot use pointers, I have to use the memory expensive way, but I will definitely try write the same function with pointers, for my own benefit!

  • 0
  On 30/04/2012 at 01:13, ~Matt~ said:

Thanks for your time guys :)

Appreciated! I understand now. But for this task I am not allowed to change the declaration of the functions, so I cannot use pointers, I have to use the memory expensive way, but I will definitely try write the same function with pointers, for my own benefit!

You can always declare the structure as a global variable and do it the cheap way memory-wise ;)

  • 0
  On 30/04/2012 at 13:30, gian said:

You can always declare the structure as a global variable and do it the cheap way memory-wise ;)

"Beware of the dark side. Globals, gotos; the dark side of the Force are they. Easily they flow, quick to join you in a fight. If once you start down the dark path, forever will it dominate your destiny, consume you it will.."

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • I think the flub is slightly funny, albeit minor. What will be funnier is the people buying some utterly terrible Chinese Android phone for $500 (that's with a huge profit margin worked in). That said, I've bemoaned this before: I miss the days when Neowin was about Microsoft products and technologies and didn't host articles that would get people riled up politically. It used to be a friendlier place where people were only bitches about insignificant things related to Microsoft.
    • AMD thinks Ryzen Threadripper 9000 wipes the floor with Intel by Sayan Sen At Computex 2025 earlier this year, AMD revealed its new Zen 5-based Ryzen Threadripper 9000 series with up to 96 cores, comprising the PRO 9000WX series and 9000 series chips. At the time though the company did not share performance numbers but given the specs, we had a fairly good idea of their capability. For those who may not be familiar with Ryzen Threadripper, it is AMD's desktop CPU lineup meant for workstations and HEDT (high-end desktop) builds and is placed between the mainstream Ryzen and the server EPYC lineups. With the launch expected to happen next month, performance numbers for the Ryzen Threadripper 9000 are now out. Before diving into the performance details, AMD has also shared a recap of some of the platform details and the compatible sTR5 socket. These new premium chips support up to 8 channels of DDR5-6400 memory and up to 128 PCIe 5.0 lanes for I/O. AMD also promises over 7000 MT/s of DDR5 support with EXPO. The specs of the Ryzen Threadripper 9000 lineup are given below: Processor SKU Cores Threads Base Clock (GHz) Boost Clock (GHz) L3 Cache (MB) Memory Channels PCIe Lanes TDP (W) AMD Ryzen Threadripper PRO 9995WX 96 192 2.5 5.45 384 8‑channel DDR5‑6400 ECC 128 PCIe Gen5 350 AMD Ryzen Threadripper PRO 9985WX 64 128 3.2 5.4 384 8‑channel DDR5‑6400 ECC 128 PCIe Gen5 350 AMD Ryzen Threadripper PRO 9975WX 32 64 3.2 5.4 384 8‑channel DDR5‑6400 ECC 128 PCIe Gen5 350 AMD Ryzen Threadripper PRO 9965WX 24 48 3.2 5.4 384 8‑channel DDR5‑6400 ECC 128 PCIe Gen5 350 AMD Ryzen Threadripper PRO 9955WX 16 32 3.2 5.4 384 8‑channel DDR5‑6400 ECC 128 PCIe Gen5 350 AMD Ryzen Threadripper PRO 9945WX 12 24 3.2 5.4 384 8‑channel DDR5‑6400 ECC 128 PCIe Gen5 350 AMD Ryzen Threadripper 9980X 64 128 3.2 5.4 256 4‑channel DDR5‑6400 92 PCIe Gen5 350 AMD Ryzen Threadripper 9970X 32 64 3.2 5.4 256 4‑channel DDR5‑6400 92 PCIe Gen5 350 AMD Ryzen Threadripper 9960X 24 48 3.2 5.4 256 4‑channel DDR5‑6400 92 PCIe Gen5 350 AMD has compared the 96-core 9995WX against the previous-gen 7995WX (images below), also with the same core configuration, and the 64-core 9980X, against Intel's 60-core Xeon W9-3595X. While Xeon has generally been associated with Server CPUs, the Xeon W chips are designed to be used in workstations. AMD follows a similar naming, too, wherein the W in the WX is meant to indicate workstation, and the non-W Threadripper is for HEDT. AMD claims up to 26% faster throughput on the newer 96-core 9995WX compared to the 7995WX. Meanwhile, against the Intel Xeon w9-3595X, AMD expects utter dominance from its 9980X with up to 108% faster performance. Even the lowest gain, says the company, is 22% over the Intel chip, and that is still very significant. AMD also compared the AI performance of the 9995WX vs the Xeon w9-3595X. The company promises up to 49% faster LLM processing, but keep in mind that the figures given include a GPU as well. Besides AI, performance related to other creative and professional workloads was also shared. In Keyshot rendering, for example, AMD claims up to 119% gains over the Xeon SKU. And in Chaos V-Ray, the 9995WX is said to offer nearly 2.5 times the performance. AMD has not released pricing information for the Threadripper 9000 series.
    • Funk Microsoft - I would switch from PS5 as you have better deals but the Xbox interface (I tried One S and later on, even one X i hate the interface and considering all MS changes in Windows interface over the years.. I hope they have a good one coming ps5 has also weird interface I had to get used too. But considering the library of ps4 games I wanted to be playable for me… I got used and adapted
    • I loved Sonic CD so much. I think I must have almost worn out that disc!
  • Recent Achievements

    • First Post
      Ian_ earned a badge
      First Post
    • Explorer
      JaviAl went up a rank
      Explorer
    • Reacting Well
      Cole Multipass earned a badge
      Reacting Well
    • Reacting Well
      JLP earned a badge
      Reacting Well
    • Week One Done
      Rhydderch earned a badge
      Week One Done
  • Popular Contributors

    1. 1
      +primortal
      654
    2. 2
      ATLien_0
      267
    3. 3
      Michael Scrip
      218
    4. 4
      +FloatingFatMan
      188
    5. 5
      Steven P.
      146
  • Tell a friend

    Love Neowin? Tell a friend!