Good day! How are you this gloomy, rainy afternoon?

I just realized - through experimentation, naturally 😂 - that I can return whole printf()s into main. Mind blowing. Anyway, I would much appreciate any input on how to write my leapYear function more aesthetically pleasing. I tried slapping the printf statements at the end of leapYear or at the end of each if statement. Still feels repetitive…

Also, as it stands, I’m having leapYear return int as per the declaration and definition. But I am returning printf() statements. Why does this work? I know that, for instance, char is int under the hood, using the machine’s underlying character table, for instance ASCII. Is the explanaition something similar to this?

Thank you in advance! 😊

#include <stdio.h>  
#include <string.h>  

int leapYear(int year);  

int main() {  

	int year = 0;  

	printf("Enter the year that you would like to check and press ENTER: ");  
	
	scanf("%d", &year);  
	leapYear(year);  
	
	return 0;  
}  

int leapYear(int year) {  

	char wasiswill[12] = "";  

    	if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {  
	    	if (year < 2026) strcpy(wasiswill,"was");  
	    	if (year == 2026) strcpy(wasiswill, "is");  
        	if (year > 2026) strcpy(wasiswill, "will be");  
  	        goto EXIT_LEAP;  
	}  
	else {  
		if (year < 2026) {  
			strcpy(wasiswill,"was");  
			goto EXIT_NLEAP1;  
		}  
		else if (year == 2026) {  
			strcpy(wasiswill, "is");  
			goto EXIT_NLEAP2;  
		}  
		else if (year > 2026) {  
			strcpy(wasiswill, "will not be");  
			goto EXIT_NLEAP3;  
		}  
	}  
EXIT_LEAP: return printf("%d %s a leap year.\n", year, wasiswill);  
EXIT_NLEAP1: return printf("%d %s not a leap year.\n", year, wasiswill);  
EXIT_NLEAP2: return printf("%d %s not a leap year.\n", year, wasiswill);  
EXIT_NLEAP3: return printf("%d %s a leap year.\n", year, wasiswill);  
}  
  • unmagical@lemmy.ml
    link
    fedilink
    arrow-up
    5
    ·
    7 days ago

    You can do the ordinal comparison once at the start instead of for both the positive and negative case. Then track a isLeap variable and just do one printf at the end with the combination of your different variables.

    Your code feels repetitive now because it is. You’re comparing years multiple times and printing “[not?] a leap year” multiple times.

    The reason returning printf works is because the return type of printf is an int containing the count of characters printed.


    I recognize that this is besides the point, but It doesn’t make a ton of sense to attribute a Gregorian interpretation to years before the adoption of the Gregorian system, and thus to truly be honest in the response different leap rules ought to be used for pre-Gregorian years. In any case this will also return the wrong result for 0 or negative years as there aren’t negative years or a year 0.

    • printf("%s", name);@piefed.blahaj.zoneOP
      link
      fedilink
      English
      arrow-up
      3
      ·
      7 days ago

      I don’t think that you were off point at all by pointing out the factual errors by initializing at 0. I appreciate it as much as your advice on the code itself! This is just my lack of common sense and me sucking at math.

      Thank you very much for the input on how to tidy up the code! I’ll give it a shot! 😊

      • unmagical@lemmy.ml
        link
        fedilink
        arrow-up
        3
        ·
        7 days ago

        I honestly kinda love date/time manipulation stuff while coding because it’s very nature is reliant on exceptions and edge cases. While it can be annoying it is far from boring especially if your day to day is just managing ledgers or APIs. Even with my odd endeavor into date/time shenanigans though it’s almost always better to use a library as the complexity will quickly grow out of scope.

        • printf("%s", name);@piefed.blahaj.zoneOP
          link
          fedilink
          English
          arrow-up
          2
          ·
          7 days ago

          Cool insight! Also, this reminds me, where I work, we have a piece of really old, probably early 2000’s, software with which we book and document interviews with our clients (convicts on parole, infact). When I once accidentally tried to enter a future date as the date of an interview, it gave me an error message saying “you can only book interviews between 1753 and present day”. After looking into it, I found that the Gregorian calendar, in my country, was officially adopted as late as 1753 because of religious opposition. I laughed so hard at this, still wondering if this was left there as an Easter egg by a developer or if it’s using a library that behaves this way.

  • CameronDev@programming.dev
    link
    fedilink
    arrow-up
    3
    ·
    7 days ago

    This is not a good way to use GOTO :(.

    For starters: Your GOTO targets aren’t unique, NLEAP1 and NLEAP2 are the same, and LEAP and NLEAP3 are the same.

    I would probably just put the printfs where the gotos are and save the strcpys. Just make sure to return out after the printfs. Sometimes being verbose in your code is better than being clever with gotos.

    Your returns are returning the return value from the printfs.

    I.e: same as:

    int ret = printf(...);
    return ret;
    

    Printfs returns an int with the number of bytes it wrote out.

    • printf("%s", name);@piefed.blahaj.zoneOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      7 days ago

      Thank you very much for your input! 😃 How clumsy of me not to make the GOTO targets unique… Then I’ll reverse the code to what I had initially written, namely, exactly what you said.

      Could you clarify what you mean by “save the strcpys”?

      • CameronDev@programming.dev
        link
        fedilink
        arrow-up
        2
        ·
        7 days ago

        If you moved the printfs back, you’d end up with 6 printfs, and you can just hardcode in the wasiswill value in the format string.

        As it happens, the strcpys are unnecessary anyway, you can just assign “will be” to a char pointer:

        char* williswas = "";
        if (year == 2026) {
            williswas = "is";
        }
        ...
        

        The strings are already in your read only memory, you just need a pointer to them.

        Making the GOTO targets unique makes a stronger argument for just dropping the gotos entirely, because the execution flow for each of the 6 cases is now getting intertwined. You may understand it today, but in 3 months time you’ll hate reading it.