Fellas, why is this happening, especially sometimes but not other times?

Here, I run the program three times, getting the exact same correct output. On the fourth, it outputs broken numbers. The function prnStats what’s being executed.

  • nachtigall@feddit.de
    link
    fedilink
    arrow-up
    3
    ·
    edit-2
    2 years ago

    In prnStats() you do not initialise all values. The following snippet only initialises Calories = 0, the rest remains uninitialised.

     float C,F,P,L,Calories = 0;
    // is the same as
    float C;
    float F;
    float P;
    float L;
    float Calories = 0;
    

    Try this instead:

     float C,F,P,L,Calories;
    C = F = P = L = Calories = 0.0;
    

    I can’t recommend -fanalyzer option enough for finding this kind of mistakes :)

    • lofenyyOP
      link
      fedilink
      arrow-up
      2
      ·
      2 years ago

      Awesome, thank you so much!

      How do you use fanalyzer? I’m passing it as a build option in GCC, assuming that it’ll alert me of any issues on either compile or runtime.

      • nachtigall@feddit.de
        link
        fedilink
        arrow-up
        2
        ·
        edit-2
        2 years ago

        Exactly! just pass it as an argument to GCC and it will perform static analysis of the code at compile time. For example, with the code you provided, the output looks like this.

        • lofenyyOP
          link
          fedilink
          arrow-up
          2
          ·
          2 years ago

          Wow that’s cool. I had no idea GCC did stuff like this.

  • kevincox@lemmy.ml
    link
    fedilink
    arrow-up
    3
    ·
    2 years ago

    I would trying running with address and undefined behaviour sanitizers enabled. The results can often be surprising.

    Other than that look for entropy sources. Do you ever reference the current time, random numbers or anything else that could make a difference from one run to the next?

    • lofenyyOP
      link
      fedilink
      arrow-up
      1
      ·
      2 years ago

      Only a file that doesn’t change between runs. I posted a copy of the full source code in a different post here in this thread. It’s been minimised down to 105 lines. Still can’t figure out where the bug is.

      I’ll try your suggestion though, thank you!

    • lofenyyOP
      link
      fedilink
      arrow-up
      1
      ·
      2 years ago

      I tried -fsanitize=undefined and -fsanitize=unreachable with no luck. Are there other appropriate sanitizers I’m missing?

      • kevincox@lemmy.ml
        link
        fedilink
        arrow-up
        2
        ·
        edit-2
        2 years ago

        The uninitialized variables would have required -fsanitize=memory but that one can be hard to use because IIUC it requires recompiling all dependencies.

        However in this case you likely would have got a compiler warning. I recommend compiling with -Wall to start, you can then turn off a few warnings that are too noisy.

        • lofenyyOP
          link
          fedilink
          arrow-up
          1
          ·
          2 years ago

          Thanks for the help! I’ll definitely start using -Wall. I don’t know why I don’t do it by default…

  • Arthur Besse@lemmy.ml
    link
    fedilink
    arrow-up
    2
    ·
    2 years ago

    There is a lot going on here, including parts of the program not even visible in your screenshot.

    You should try to make a much smaller minimal reproducible example - in the iterative process of removing things and then re-running it to test if the bug is still present (write a shell script to automate step 2, to run it as many times as are currently necessary observe the bug) you might find the cause yourself. And if you don’t, your MRE will make it easier for others to help you.

    • lofenyyOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      edit-2
      2 years ago

      Thanks for the suggestion! I managed to squish the program down into 105 lines. This is my MRE.

      #include<stdlib.h>
      #include<confuse.h>
      
      struct entry
      	{
      	int Day;
      	long int Date;
      	float C;
      	float F;
      	float P;
      	float L;
      	};
      
      int DiaryNum;
      struct entry  *Diary;
      char DiaryPath[] = "/home/lofenyy/.config/Calorimeter/Diary";
      
      cfg_opt_t entry_opts[] = 
      	{
      	CFG_INT("Date", 0, CFGF_NONE),
      	CFG_INT("Day", 0, CFGF_NONE),
      	CFG_FLOAT("C", 0, CFGF_NONE),
      	CFG_FLOAT("F", 0, CFGF_NONE),
      	CFG_FLOAT("P", 0, CFGF_NONE),
      	CFG_FLOAT("L", 0, CFGF_NONE),
      	CFG_END()
      	};
      
      cfg_opt_t entry_base_opts[] =
      	{
      	CFG_SEC("Entry", entry_opts, CFGF_MULTI),
      	CFG_END()
      	};
      
      int lodEntry()
      	{
      	//Initialization
      	cfg_t *cfg;
      	cfg_t *cfg_entry;
      	cfg = cfg_init(entry_base_opts, CFGF_NONE);
      	
      	//Open our file and check for errors
      	if(cfg_parse(cfg, DiaryPath) == CFG_PARSE_ERROR)
      		printf("Err!\n");
      	
      	//Allocate enough memory for our internal diary
      	DiaryNum = cfg_size(cfg, "Entry");
      	Diary = malloc(DiaryNum * sizeof(struct entry));	
      	
      	//For every entry in our external diary
      	for(int C = 0;C < cfg_size(cfg, "Entry");C++)
      		{
      		//Copy our entries to our internal diary
      		cfg_entry = cfg_getnsec(cfg, "Entry", C);
      		Diary[C].Date	= cfg_getint(cfg_entry, "Date");
      		Diary[C].Day	= cfg_getint(cfg_entry, "Day");
      		Diary[C].C	= cfg_getfloat(cfg_entry, "C");
      		Diary[C].F	= cfg_getfloat(cfg_entry, "F");
      		Diary[C].P	= cfg_getfloat(cfg_entry, "P");
      		Diary[C].L	= cfg_getfloat(cfg_entry, "L");
      		}
      	
      	cfg_free(cfg);
      	}
      
      double getEntryCalories(int C)
      	{
      	//4 calories per carb and protein. 9 per lipid. 
      	return 4*(Diary[C].C+Diary[C].P)+9*(Diary[C].L);
      	}
      
      int prnStats()
      	{
      	float C,F,P,L,Calories = 0;
      	int day0 = Diary[0].Day;
      	int day1 = Diary[DiaryNum -1].Day;
      	int days = (day1 - day0) +1;
      	
      	//For every diary entry
      	for(int i = 0;i < DiaryNum;i++)
      		{
      		//Count up our nutrients
      		C = C + Diary[i].C;
      		F = F + Diary[i].F;
      		P = P + Diary[i].P;
      		L = L + Diary[i].L;
      		Calories = Calories + getEntryCalories(i);
      		}
      	
      	//Print them out
      	printf("Average Calories: %2.2f\n", (float)(Calories/days));
      	printf("Average Carbs: %2.2f\n", (float)(C/days));
      	printf("Average Fibre: %2.2f\n", (float)(F/days));
      	printf("Average Proteins: %2.2f\n", (float)(P/days));
      	printf("Average Lipids: %2.2f\n", (float)(L/days));
      	}
      
      int main(int argc, char  *argv[])
      	{
      	// Load our internal food diary from our external food diary
      	// print out our statistics
      	lodEntry();
      	prnStats();
      	}
      

      This is the contents of Diary

      Entry
      {
      	Date = 1679542784
      	Day = 0
      	C = 6.000000
      	F = 5.000000
      	P = 4.000000
      	L = 3.000000
      }
      
      Entry
      {
      	Date = 1679546112
      	Day = 0
      	C = 60.000000
      	F = 50.000000
      	P = 20.000000
      	L = 1.000000
      }
      
      Entry
      {
      	Date = 1679547008
      	Day = 0
      	C = 4.000000
      	F = 4.000000
      	P = 4.000000
      	L = 4.000000
      }
      
      Entry
      {
      	Date = 1679547136
      	Day = 1
      	C = 4.000000
      	F = 4.000000
      	P = 4.000000
      	L = 4.000000
      }
      
      Entry
      {
      	Date = 1679547136
      	Day = 5
      	C = 60.000000
      	F = 50.000000
      	P = 20.000000
      	L = 1.000000
      }
      
    • lofenyyOP
      link
      fedilink
      English
      arrow-up
      1
      ·
      2 years ago

      Is this likely the case if the program runs only in a single thread?