Using empty char in C - c

I want to use the ternary operator and an empty char '' to spell correctly the word "neightbor" (with or without a "s").
I want to do the following :
printf("There is %d neightbor%c\n", nbNeighbors, (nbNeighbors>1)?'s':'');
obviously, I get an arror error: empty character constant
How can I menage to use this trick to get the right spelling in one printf ?

You could use a non-printable character but they may end up looking like something else.
You'd be better off using strings:
printf("There %s %d neighbor%s\n",
nbNeighbors != 1 ? "are" : "is",
nbNeighbors,
nbNeighbors != 1 ? "s" : ""
);

OP: "I want to use the ternary operator..."
Unless the exercise is to practice the ternary operator, committing to a particular technique blinds one to possibilites.
The example below uses 'branchless' code to deliver a grammatically correct result (ignoring the American spelling of "neighbour".)
printf( "There %s %d neighbor%s\n",
"are\0is" + (nbNeighbors == 1)*4,
nbNeighbors,
"s" + (nbNeighbors == 1) );
I'd never recommend manipulating the truth, but manipulating a truth value can come in handy sometimes.
EDITThe above may be difficult for some to read/understand.
Below is the same thing expressed slightly differently:
printf( "There %s %d neighbor%s\n",
!(nbNeighbors-1)*4 + "are\0is",
nbNeighbors,
!(nbNeighbors-1) + "s" );
Tested, functional and branchless.

Related

removing multi-char constants in C

Here's some code I found in a very old C library that's trying to eat whitespace from a file...
while(
(line_buf[++line_idx] != ' ') &&
(line_buf[ line_idx] != ' ') &&
(line_buf[ line_idx] != ',') &&
(line_buf[ line_idx] != '\0') )
{
This great thread explains what the problem is, but most of the answers are "just ignore it" or "you should never do this". What I don't see, however, is the canonical solution. Can anyone offer a way to code this test using the "proper way"?
UPDATE: to clarify, the question is "what is the proper way to test for the presence of a string of one or more characters at a given index in another string". Forgive me if I am using the wrong terminology.
Original question
There is no canonical or correct way. Multi-character constants have always been implementation defined. Look up the documentation for the compiler used when the code was written and figure out what was meant.
Updated question
You can match multiple characters using strchr().
while (strchr( " ,", line_buf[++line_idx] ))
{
Again, this does not account for that multi-char constant. You should figure out why that was there before simply removing it.
Also, strchr() does not handle Unicode. If you are dealing with a UTF-8 stream, for example, you will need a function capable of handling it.
Finally, if you are concerned about speed, profile. The compiler might get you better results using the three (or four) individual test expressions in the ‘while’ condition.
In other words, the multiple tests might be the best solution!
Beyond that, I smell some uncouth indexing: the way that line_idx is updated depends on the surrounding code to actuate the loop properly. Make sure that you don’t create an off-by-one error when you update stuff.
Good luck!
UPDATE: to clarify, the question is "what is the proper way to test
for the presence of a string of one or more characters at a given
index in another string". Forgive me if I am using the wrong
terminology.
Well, there are a number of ways, but the standard way is using strspn which has the prototype:
size_t strspn(const char *s, const char *accept);
and it cleverly:
calculates the length (in bytes) of the initial segment of s
which consists entirely of bytes in accept.
This allows you to test for the "the presence of a string of one or more characters at a given index in another string" and tells you how many of the characters from that string were sequentially matched.
For example, if you had another string say char s = "somestring"; and wanted to know if it contained the letters r, s, t, say, in char *accept = "rst"; beginning at the 5th character, you could test:
size_t n;
if ((n = strspn (&s[4], accept)) > 0)
printf ("matched %zu chars from '%s' at beginning of '%s'\n",
n, accept, &s[4]);
To compare in order, you can use strncmp (&s[4], accept, strlen (accept));. You can also simply use nestest loops to iterate over s with the characters in accept.
All of the ways are "proper", so long as they do not invoke Undefined Behavior (and are reasonable efficient).

Can sscanf be used to match wildcards?

For instance consider an array of C strings, all digits
..."12334", "21335", "24335"...
and I want to know how many of these strings matches this wildcard mask
**33* (where * = any digit 0-9)
Could I use sscanf(str, mask, ...) to accomplish this? The format "%1d%1d%[3]%[3]%1d" seems to match more than I want (when 33 isn't there) and "%1d%1d33%1d" seems to behave weirdly, matching some but not all matching entries.
The context in my code:
if (sscanf(array[i], mask, &a1, &a2, &a3) == 3)
3 being the number of wildcard digits matched.
The format "%1d%1d33%1d" should be correct, assuming your inputs are all numbers. But you haven't told us what specific inputs it's failing on. You should consider that the strings "1 2334" and " 1\n\n233 \t 4" would actually match because %d will eat whitespace until it finds an integer.
Beware that if you were to use "%2d33%1d" this would be even worse, because a 2-character integer can be a single digit with a negative.
In case it's not already apparent, using sscanf for this type of matching is not appropriate. You are better off using a regular expressions library, which excel at this kind of thing.
However, by far the simplest approach, if you just want something quick that works, is to use short-circuit evaluation along with isdigit. You don't even need to check the string length:
int matches( const char * s )
{
return s
&& isdigit(s[0])
&& isdigit(s[1])
&& '3' == s[2]
&& '3' == s[3]
&& isdigit(s[4]);
}

How printf works without modifiers?

#include <stdio.h>
int main()
{
char string[]="Programming Language";
printf(string);
printf("\n%s",string);
return 0;
}
Output
Programming Language
Programming Language
Why is the output same?
When printf parses the format string it prints the characters that are not format specifiers as they are.
So when it parses "Programming Language" it just echoes each character.
The first printf statement is the same as:
printf("Programming Language");
and your second printf statement is just the same:
(Because the 'placeholder' gets replaced with the variable, + a new line at the start)
printf("\nProgramming Language");
So that's why it is the same output
They are not the same. The second one includes a new line that is not included in the first one.
If you remove the newline, they will be the same because:
The first version simply prints the contents of string.
The second version uses %s, which is replaced with the contents of string.
Either way, the result would be the same.
First argument of printf could contains plain text besides modifiers. So basically it equals. %s is useful when you want to include some string inside of other e.g.:
printf ("One Two %s Four Five (%d, %d, %d, %d, %d)", "Three", 1, 2, 3, 4, 5);
Using %s modifier standalone quite meaningless. Just one thing you should remember - in the case you are not using %s modifier and pass string as a first parameter you should quote % symbol. E.g.:
printf ("I am 100%% sure that it would works!");
So basically instead just single % sign you need to use double % ( %% ). Even in the case you pass it as a variable:
char s [] = "50%% complete";
printf (s);
Hope it makes sence!

Efficient way to extract formatted data in C

I have a string of the form
[S{i,j} : this is stack overflow]
I want to extract i,j and this is stack overflow in two separate strings.
sscanf will not work here as strings to be extracted can have spaces.
Can anyone please suggest an efficient way to do this?
If the string cannot contain the ending square bracket, you can absolutely use sscanf():
int i, j;
char text[128];
if( sscanf(input, "[S{%d,%d} : %127[^]]", &i, &j, text) == 3 )
{
printf("got it all!\n");
}
For more information about the somewhat lesser known conversion specifier [, see for instance this manual page. Basically, the conversion %[^]] means "all characters except a closing square bracket, it's a special form of the syntax using both negation (^) and doubling the closing bracket to include it in the set of negated characters.
UPDATE If you really mean "in two separate strings", then of course the above is wrong since it parses out the numbers into int-type variables. To get the pair as a string, use something like:
char ij[32], text[128];
if( sscanf(input, "[S{%31[^}]} : %127[^]]", ij, text) == 2 )
{
}

Why is this not working with printf() in c

I have the following code:
int i=1;
printf((i==1)?" ":" " "hello");
printf(" " "hello");
And I am astonished to see that the first printf only gives a space as output and the second printf outputs a space followed by the string hello. I was expecting output like second one in case of first one. But is there something here I am missing. Please help me with this ...
String literal joining is a lexical feature, which means this:
(i==1) ? " " : " " "hello"
is the same as this:
(i==1) ? " " : " hello"
It should now be pretty obvious why you get the result you get.
i == 1 is true, so the ternary operator evaluates to the first of the two options, " ". Not at all surprising.
C automatically combines two adjacent string literals together.
So your parameter to the second printf: " " "hello" gets joined together to become " hello", which is then printed out normally.
Other answers have explained why your first printf works the way it does, which should be pretty obvious.
Since the condition tested in the ternary operator (i==1) evaluates to true, it returns the expression right after the ?.
The semantics of the ternary operator are something like this:
test_something?if_true:not_true
Your printf statement works as it should.
The source of your confusion is the misunderstanding of when the concatenation is performed. Joining two consecutive string literals is done by the compiler at compile time, not by your program at run time. Therefore there is only one way to parse the first printf: both string literals belong to the "else" branch of the expression. You can test it by setting i to zero and observing the output.

Resources