21

I have to write a program in which main calls other functions that test a series of number if any are less than a number, if all the series' numbers are between two limits, and if any are negative.

My code returns the values of 1 for true and 0 for false, but the assignment asks that they be printed as 'true' or 'false'. I'm not sure how to get the bool answers to print as a string from printf. I used if (atl == false) printf("false"); in my at_least.c file and in file main.c, but it returns only a long string of true or false (example: truetruetrue....).

I'm not sure if that is the correct coding and I'm putting it in the wrong spot or there was some other code that I need to use.

This is my main.c file:

#include "my.h"

int main (void)
{
    int     x;
    int     count    = 0;
    int     sum      = 0;
    double  average  = 0.0;
    int     largest  = INT_MIN;
    int     smallest = INT_MAX;
    bool    atlst    = false;
    bool    bet      = true;
    bool    neg      = false;
    int     end;

    while ((end = scanf("%d",&x)) != EOF)
    {
        sumall(x, &sum);                        // Calling function sumall
        count++;
        larger_smaller(x, &largest, &smallest); // Calling function larger_smaller
        if (atlst == false)
           at_least(x, &atlst);                 // Calling function at_least if x < 50
        if (bet == true)
           between(x, &bet);                    // Calling function between if x is between 30 and 40 (inclusive)
        if (neg == false)
           negative(x, &neg);                   // Calling function negative if x < 0
    }

    average = (double) sum / count;
    print(count, sum, average, largest, smallest, atlst, bet, neg);
    return;
 }

My results for a set of numbers:

The number of integers is:           15
The sum is               :         3844
The average is           :       256.27
The largest is           :          987
The smallest is          :          -28
At least one is <  50    :            1     // This needs to be true
All between  30 and  40  :            0     // This needs to be false
At least one is negative :            1     // This needs to be true

This is in C, which I can't seem to find much on.

Addendum:

This is repeated from an answer below.

This worked for the at_least and negative functions, but not for the between function. I have

void between(int x, bool* bet)
{
    if (x >= LOWER && x <= UPPER)
        *bet = false;
    return;
}

as my code. What's wrong?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Piseagan
  • 521
  • 3
  • 6
  • 12
  • 2
    Just a side note, `x == true` is redundant in a Boolean expression; you can just say `x`. Similarly, `x == false` is just `!x`. – Jon Purdy Oct 01 '11 at 20:57
  • Possible duplicate of [What is the printf format specifier for bool?](https://stackoverflow.com/questions/17307275/what-is-the-printf-format-specifier-for-bool) – Brad Solomon Jul 25 '19 at 01:35

5 Answers5

50

Alternate branchless version:

"false\0true"+6*x
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 19
    An inline function or macro with a self-documenting name (e.g. `bool2str`) would fix that. – R.. GitHub STOP HELPING ICE Oct 01 '11 at 15:07
  • 1
    Sorry to bring this ancient question up again, but I figured I'd say that I like the solution, but a macro wouldn't work unless x was casted to a BOOL which could only be a 1 or a 0. This one took me a minute to figure out. – Josh The Geek Aug 27 '13 at 01:40
  • 3
    @JoshTheGeek: Yes, I didn't mean for it to be copied verbatim to a macro. There are a few changes you'd need to make like proper parentheses and collapse of the value to 0/1. `("false\0true"+6*!!(x))` is probably the cleanest way. – R.. GitHub STOP HELPING ICE Aug 27 '13 at 05:14
  • 5
    What does this actually do? Would you provide a little detail for those of us learning c who stumble upon this answer? – William Everett May 29 '15 at 22:06
  • 2
    This code is obfuscated and not Unicode compatible. For junior engineers whom I'm trying to educate on how to write maintainable code, I would hold this up as an antipattern. Certainly it wouldn't pass code review. – ArchaeaSoftware Jun 26 '15 at 03:20
  • 5
    @ArchaeaSoftware: I have no idea what you mean by "not Unicode compatible". The only possible Unicode representation of a char string is UTF-8. But even if you did have a `wchar_t` string (`L` prefix), the code is still valid, because pointer addition is in terms of array elements, not bytes. Your comment suggests a lack of understanding of the C language. – R.. GitHub STOP HELPING ICE Jun 26 '15 at 03:22
  • 2
    I understand the C language just fine. I also understand the importance of maintenance programmers being able to divine the meaning of code with a minimum of head-scratching. Your answer (which amazingly received 13 upvotes) and comment suggest a lack of understanding of software engineering. – ArchaeaSoftware Jun 26 '15 at 15:22
  • 4
    @WilliamEverett: The expression `"false\0true"` actually evaluates to a `const char*` pointing to that particular string in the program's memory. `+6*x` adds 6 to that pointer if `x` is 1 (true) and 0 if `x` is 0 (false). If 0 is added to the pointer, `printf` will start to read at the '`f`' and will stop to read when it reaches '`\0`' (the null termination character). If instead 6 is added, `printf` will start to read at the '`t`' and stop to read when the string terminates naturally. The construct will however fail if `x` is not 0 or 1, so you need @R's fix if you can't guarantee that it is. – HelloGoodbye Jun 30 '15 at 16:39
  • @R: An inline function or macro with a self-documenting name would help, but I'm afraid people would still be very confused by the construct. A comment explaining the mechanics behind the trick would be also be appropriate. – HelloGoodbye Jun 30 '15 at 16:45
  • 2
    This is wicked cool. Clang gave me a warning "warning: adding 'int' to a string does not append to the string [-Wstring-plus-int]". Instead of having the binary plus operator, which might confuse someone into thinking they're correctly performing string concatenation with implicit type conversion. Writing the code as `&"false\0true"[6 * x]` appeases the compiler. – Nick Desaulniers Oct 15 '15 at 18:05
  • 5
    This can be optimized to avoid a mul and use a shift instead (which is still a relevant optimization on most cpus/platforms): `"false\0\0\0true"+8*x` – jstine Jul 06 '16 at 17:37
  • I agree with @ArchaeaSoftware. I think what he meant by "not Unicode compatible" is that if the strings are translated into languages that require the use of non-ASCII Unicode encoding the number 6 might have to be changed. In fact, if the strings are changed at all, the number 6 might have to be changed. For example, if x is true Russian "ложь\0истина" + 6*x would print "ь" the last letter in the Russian word for false, because in UTF-8 encoding that word occupies 8 bytes rather than 5. The number 6 would have to be changed to 9. "❌\0✅" + 6*x would print "�". Here the number 6 has to be 4. – Thomas Hedden Feb 07 '22 at 19:52
28

You could use C's conditional (or ternary) operator:

  (a > b) ? "True" : "False";

Or perhaps in your case:

  x ? "True" : "False";
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
17

x ? "true" : "false"

The above expression returns a char *, thus you can use like this:

puts(x ? "true" : "false"); or printf(" ... %s ... ", x ? "true" : "false");

You may want to make a macro for this.

Oscar Korz
  • 2,457
  • 1
  • 18
  • 18
4

Use this one:

#include <stdio.h>

#define BOOL_FMT(bool_expr) "%s=%s\n", #bool_expr, (bool_expr) ? "true" : "false"

int main(int iArgC, char ** ppszArgV)
{
    int x = 0;
    printf(BOOL_FMT(x));

    int y = 1;
    printf(BOOL_FMT(y));

    return 0;
}

This prints out the following:

x=false
y=true

Using this with type bool, but int should work the same way.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
alk
  • 69,737
  • 10
  • 105
  • 255
  • You probably want to add the `printf` call into the macro. Although because of how the comma operator works, you can use extra parentheses to do stuff like `puts((BOOL_FMT(1)))` to print `true`. – Oscar Korz Oct 01 '11 at 17:27
2

I have three arrays for that:

strbool.c:

#include "strbool.h"

const char alx_strbool[2][6]    = {"false", "true"};
const char alx_strBool[2][6]    = {"False", "True"};
const char alx_strBOOL[2][6]    = {"FALSE", "TRUE"};

strbool.h:

#pragma once

/* rename without alx_ prefix */
#if defined(ALX_NO_PREFIX)
#define strbool     alx_strbool
#define strBool     alx_strBool
#define strBOOL     alx_strBOOL
#endif

extern  const char alx_strbool[2][6];
extern  const char alx_strBool[2][6];
extern  const char alx_strBOOL[2][6];

Disclaimer: The prefixes are necessary because names starting with str are reserved (actually, only strbool), but until they are actually used by C or POSIX, I will use the short version.

It's very simple to use them:

#include <stdio.h>

#define ALX_NO_PREFIX
#include "strbool.h"

int main(void)
{
        int var = 7;

        printf("var is %s\n", strBool[!!var]);

        return 0;
}
var is True
  • The conversion to bool seems a bit out of the question and unpractical to use. Maybe defining strbool this way would make it more natural? `#define strbool(x) alx_strbool[!!(x)]` – Vélimir Dec 26 '21 at 01:17
  • 1
    @Sho Yes, that could be an option. In case a function seems more natural to use, I'd write an `inline` function and accept a `bool` parameter instead of a function-like macro; that would be the most readable/intuitive thing. Anyway, just remember that the identifier `strbool()` is potentially reserved by the standard. Note that I said potentially reserved, and not reserved, since C2x acknowledges that potentially reserved identifiers that are not in use by the standard are not (yet) reserved. – alx - recommends codidact Dec 26 '21 at 14:22