Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


C If Statement Question


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 NUCLEAR RABBIT   Members   -  Reputation: 254

Like
3Likes
Like

Posted 03 February 2014 - 09:58 PM

Hello! 

 

I am taking a C programming class and my teacher uses the "puts statement" to combine an if statements with the action if the condition is met. I saw too different examples of doing the same thing and was just wondering which method is more "standardized" and which method is not recommended using? It's nothing too serious, but it got me curious. thanks! 

 

PS - here's an example:

#include <stdio.h>

int main(int argc, const char * argv[])
{
    int grade;
    
    // gets user input
    printf("What is the students grade? ");
    scanf("%d", &grade);
    
    // alerts user if passed or failed
    (grade >= 60) ? printf("Passed!\n") : printf("Uh-ohhh...\n");
    // puts statement version
    puts(grade >= 60 ? "Passed!\n" : "Uh-ohhh...\n");
    
    // displays grade
    if(grade >= 90)
        printf("Grade = A\n");
    else if(grade >= 80)
        printf("Grade = B\n");
    else if(grade >= 70)
        printf("Grade  = C\n");
    else if(grade >= 60)
        printf("Grade = D\n");
    else
        printf("Student failed.\n");
    
    return 0;
}

------------------------My band: RISE OVER ME!

Sponsor:

#2 Josh Petrie   Moderators   -  Reputation: 3887

Like
5Likes
Like

Posted 03 February 2014 - 10:21 PM

This sort of thing is generally considered "bad" (using a ternary operator to wholly replace an if-statement):

 

(grade >= 60) ? printf("Passed!\n") : printf("Uh-ohhh...\n");

 

Generally, you should prefer an if statement to the ternary operator if the operands to the ?: are verbs or complex expressions with side-effects (as they are above: printing). 

 

The second example is a more acceptable use of the ternary operator:

 

puts(grade >= 60 ? "Passed!\n" : "Uh-ohhh...\n");

 


Josh Petrie | Game Developer, Undead Labs


#3 dejaime   Crossbones+   -  Reputation: 4119

Like
5Likes
Like

Posted 03 February 2014 - 10:23 PM

Actually, puts() only shows a message and has nothing to do with the if statement there.

Your teacher is using a not as readable version of:

if (grade >= 60)
        puts("Passed!\n");
else
        puts("Uh-ohhh...\n");

But this <condition> ? <this if true> : < this if false> syntax is only  a "conditional value attribution" or simple "conditional call", but has nothing to do with the puts() function.

 

He could have used printf in this case as well, just like this:

printf (grade >= 60 ? "Passed!\n" : "Uh-ohhh...\n");

It would work just the same.


Edited by dejaime, 03 February 2014 - 10:39 PM.


#4 frob   Moderators   -  Reputation: 22770

Like
9Likes
Like

Posted 04 February 2014 - 12:22 AM

The only thing in the OP's code block that causes me any concern is that scanf. That would immediately fail my code review. When scanf and fscanf fail they leave the input stream in an uncertain state, the functions can trivially cause bugs and buffer overflow exploits, and using it correctly is surprisingly difficult. Run that program with any invalid input (any non-numerical value will do) and your program is instantly in "undefined behavior" territory.


The various options for flow control and conditional expressions are all just fine. I wouldn't think twice about them in a review. I would prefer the version that is used to select different parameters rather than the version that calls two functions because it reduces duplication, but if you were calling different functions it would be fine.

The conditional operator can really help clean up code in some places, making it easier to read and maintain.

The conditional operator can also clutter up the code, making it harder to read and maintain.

I'd much rather see an if/else chain than a bunch of nested ternary expressions.

Otherwise, any of the overall patterns works.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#5 dejaime   Crossbones+   -  Reputation: 4119

Like
0Likes
Like

Posted 04 February 2014 - 12:26 AM


Run that program with any invalid input (any non-numerical value will do) and your program is instantly in "undefined behaviour" territory.
I can even see it happening: all output happening virtually instantly and it returns 0, as if nothing had gone wrong.

#6 Mnemotic   Members   -  Reputation: 340

Like
0Likes
Like

Posted 04 February 2014 - 12:44 AM

This is just a nitpick, but I believe that `int main(int argc, const char * argv[])` is, in fact, not a valid signature for `main` function. Standard sayeth `int main(void)`, `int main(int argc, char* argv[])` or equivalent.



#7 frob   Moderators   -  Reputation: 22770

Like
5Likes
Like

Posted 04 February 2014 - 01:35 AM

This is just a nitpick, but I believe that `int main(int argc, const char * argv[])` is, in fact, not a valid signature for `main` function. Standard sayeth `int main(void)`, `int main(int argc, char* argv[])` or equivalent.

The topic line of the thread says this is c, not c++.

In c you can use char* argv[], char** argv, const char* argv[], or const char** argv as you see fit thanks to different rules on function declarator adjustments. However, const char* const* argv is right out. The critical condition is c's less restrictive type equivalence system.

The values and the strings are modifiable, but that doesn't mean the lvalues that are created must be non-const. If the language followed C++ rules, then yes, you are correct because in C++ const modifies the signature.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#8 Mnemotic   Members   -  Reputation: 340

Like
0Likes
Like

Posted 04 February 2014 - 05:00 AM

Huh! I didn't know that. Thanks for the correction.



#9 cozzie   Members   -  Reputation: 1770

Like
0Likes
Like

Posted 04 February 2014 - 04:07 PM

I personally don't 'like' the 'large' set of if statements (personal probably..).

But honestly I don't know how you can handle it differently, since a switch statement won't take operators < or >



#10 Álvaro   Crossbones+   -  Reputation: 13929

Like
0Likes
Like

Posted 04 February 2014 - 04:51 PM

It is generally a good idea to keep input, output and computation separate. In that spirit, it would be good to have something like this function:

 

enum Grade {
  Grade_F,
  Grade_D,
  Grade_C,
  Grade_B,
  Grade_A,
};

enum Grade compute_grade(int score) {
  static int const grade_cuts[4] = {60, 70, 80, 90};
  int grade;

  for (grade = 0; grade < 4; ++grade)
    if (score < grade_cuts[grade])
      break;

  return grade;
}


#11 cozzie   Members   -  Reputation: 1770

Like
0Likes
Like

Posted 04 February 2014 - 05:44 PM

That looks and feels much cleaner, although maybe a bit off topic :)

#12 Paradigm Shifter   Crossbones+   -  Reputation: 5438

Like
1Likes
Like

Posted 04 February 2014 - 06:11 PM

4 looks like a bit of a magic number though, Al, I am disappoint.


"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#13 NUCLEAR RABBIT   Members   -  Reputation: 254

Like
0Likes
Like

Posted 04 February 2014 - 08:50 PM

Thanks for the replies! Just one more question, not too sure I understand correctly, but how come you created the Grade enum but don't use it in the code and also how come you had it returns an int instead of enum in the compute_grade function? Much appreciated! biggrin.png

 

 

It is generally a good idea to keep input, output and computation separate. In that spirit, it would be good to have something like this function:

enum Grade {
  Grade_F,
  Grade_D,
  Grade_C,
  Grade_B,
  Grade_A,
};

enum Grade compute_grade(int score) {
  static int const grade_cuts[4] = {60, 70, 80, 90};
  int grade;

  for (grade = 0; grade < 4; ++grade)
    if (score < grade_cuts[grade])
      break;

  return grade;
}

------------------------My band: RISE OVER ME!

#14 NUCLEAR RABBIT   Members   -  Reputation: 254

Like
0Likes
Like

Posted 04 February 2014 - 09:47 PM

Never mind my last questions, I played around with the code you gave me and got whats going on, thanks! cool.png

 

 

Thanks for the replies! Just one more question, not too sure I understand correctly, but how come you created the Grade enum but don't use it in the code and also how come you had it returns an int instead of enum in the compute_grade function? Much appreciated! biggrin.png

 

 

It is generally a good idea to keep input, output and computation separate. In that spirit, it would be good to have something like this function:

enum Grade {
  Grade_F,
  Grade_D,
  Grade_C,
  Grade_B,
  Grade_A,
};

enum Grade compute_grade(int score) {
  static int const grade_cuts[4] = {60, 70, 80, 90};
  int grade;

  for (grade = 0; grade < 4; ++grade)
    if (score < grade_cuts[grade])
      break;

  return grade;
}

 


Edited by NUCLEAR RABBIT, 04 February 2014 - 09:48 PM.

------------------------My band: RISE OVER ME!

#15 Álvaro   Crossbones+   -  Reputation: 13929

Like
1Likes
Like

Posted 05 February 2014 - 05:27 AM

4 looks like a bit of a magic number though, Al, I am disappoint.


Well, I could have left the size of the array implicit in the initialization, and then used sizeof(grade_cuts)/sizeof(*grade_cuts) to recover the 4 in the loop, but I think that would have detracted from the code's clarity, which would be especially bad "For Beginners". In C++ (especially C++11) there are better solutions, but this is a C thread.

EDIT: Here's a version with no magic numbers, and with the grade cuts defined in one place and one place only. If you want to understand how it works, ask Shiftie. smile.png
 

#include <stddef.h>

#define ARRAY_LENGTH(X) (sizeof(X) / sizeof(*X))

#define GRADES_AND_CUTS \
  G_A_C(F, 0)		\
  G_A_C(D, 60)		\
  G_A_C(C, 70)		\
  G_A_C(B, 80)		\
  G_A_C(A, 90)

#define G_A_C(X,Y) Grade_##X ,
enum Grade { GRADES_AND_CUTS };
#undef G_A_C

enum Grade compute_grade(int score) {
#define G_A_C(X,Y) Y ,
  static int const grade_cuts[] = {GRADES_AND_CUTS};
#undef G_A_C
  unsigned grade;

  for (grade = 1; grade < ARRAY_LENGTH(grade_cuts); ++grade)
    if (score < grade_cuts[grade])
      break;

  return grade - 1;
}

char const *grade_name(enum Grade grade) {
#define G_A_C(X,Y) #X ,
  static char const *grade_name_table[] = {GRADES_AND_CUTS};
#undef G_A_C
  return grade_name_table[grade];
}


Edited by Álvaro, 06 February 2014 - 02:52 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS