C: Printing from char array produces erroneous characters - c

Solutions for K. N. King's C Programming: A Modern Approach, 2nd Edition, Chapter 8, Programming Project 14, produces different outputs both correct and incorrect. Examples shown below:
Reversal of sentence: you can't swallow a cage can you?
Reversal of sentence: you can't swallow a cage can you�(�?
Reversal of sentence: you can't swallow a cage can you��x�?
Reversal of sentence: you can't swallow a cage can you�Ց�?
As shown by the example input, correct output should be:
Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: you can't swallow a cage can you?
My own solution and below solution (courtesy of Github user #williamgherman; slightly modified for sake of readability) both produces the different outputs.
#include <stdio.h>
int main(void)
{
char ch, terminator, sentence[100] = {0};
int i = 0, j;
printf("Enter a sentence: ");
for (i = 0; (ch = getchar()) != '\n' && i < 100; i++) {
if (ch == '.' || ch == '!' || ch == '?') {
terminator = ch;
break;
}
sentence[i] = ch;
}
printf("Reversal of sentence: ");
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0)
;
j = i == 0 ? 0 : i + 1;
while (sentence[j] != ' ' && sentence[j] != '\0')
putchar(sentence[j++]);
if (i > 0)
putchar(' ');
}
printf("%c\n", terminator);
return 0;
}
Despite double checking the code, and running through the example input on paper, I've not been able to find an answer.
How come the code produces these different outputs, correct as well as incorrect? What produces the erroneous characters?

Most likely, the problem is with the exit condition for the while loop used to print the sentence in reverse
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0) ;
....
Consider the case where the code is going to print the first word (i=3):
The second while will decrement i all the way to 0
then the code will print the word 'you' (positions 0 to 2, inclusive)
At this point i=0, the first while still is true
The second while will decrement i to -1, and will continue to decrement it to -2, -3, until a space is found.
The code will print the word with indices of -1, -2, -3, and will print a string based on those undefined values.

Yes, as stated in the answer above the problem is within this block
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0) ;
....
You should change the i != 0 part into i >= 0, this should solve the thing
The problem is that i decrementation sentence[--i] happens before i != 0 and so imagine the while loop starting with i = 0 - this will mean that sentence[i - 1] will (likely) not be ' ' and i will not be equal to zero.

For starters the program has undefined behavior because the variable terminator is not initialized. The user can press the Enter key without supplying one of these characters ".!?"
for (i = 0; (ch = getchar()) != '\n' && i < 100; i++) {
^^^^^^^
In this case this statement
printf("%c\n", terminator);
will output an indeterminate value.
Moreover the user can interrupt the loop pressing a corresponding key combination but the loop does not process such a situation.
If the user pressed the Enter key in the very beginning of the loop then i will be equal to 0 In this case the inner while loop
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0)
^^^
;
will invoke undefined behavior.
Moreover before the terminating character (".!?") the sentence can contain spaces. Thus this loop
while (sentence[--i] != ' ' && i != 0)
;
j = i == 0 ? 0 : i + 1;
again will be incorrectly terminated. That is j will be equal to i + 1 where a zero character is stored (provided that the user did not entered all 100 elements of the array sentence).
Apart from this the program does not output existent number of spaces between words. It only tries to output one space
putchar(' ');
Take into account that the user can enter for example the tab character '\t' instead of the space character ' '.
Below there is shown how the program can be written.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
const char *punctuation = ".?!";
enum { N = 100 };
char s[N] = "";
char terminator = '\0';
printf( "Enter a sentence: " );
size_t n = 0;
for ( int c; n < N && ( c = getchar() ) != EOF && c != '\n'; n++ )
{
if ( strchr( punctuation, c ) )
{
terminator = c;
break;
}
s[n] = c;
}
printf( "Reversal of sentence: " );
putchar( '\"' );
size_t i = 0;
while ( i != n && isblank( ( unsigned char )s[i] ) ) putchar( s[i++] );
for ( size_t j = n; i != n; )
{
while ( i != n && !isblank( ( unsigned char )s[i] ) ) i++;
while ( isblank( ( unsigned char )s[j-1] ) ) j--;
size_t k = j;
while ( j != 0 && !isblank( ( unsigned char )s[j-1] ) ) j--;
for ( size_t l = j; l != k; l++ ) putchar( s[l] );
while ( i != n && isblank( ( unsigned char )s[i] ) ) putchar( s[i++] );
}
if ( terminator ) putchar( terminator );
putchar( '\"' );
return 0;
}
The program output might look like
Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: "you can't swallow a cage can you?"
As you can see the program preserved all spaces contained in the entered sentence.

Related

Identifies the differences between pairs of strings

I'm going to identify the difference between two string. I can't see what I'm missing here. The output from my code is correct by the sample. But when I test run it with other test, it fails. I can't see what the other tests are.
The input:
The first line of input contains an integer 1<= n <= 500, indicating the number of test cases that follow. Each test case is a pair of lines of the same length, 1 to 50 characters. Each string contains only letters (a-z,A-Z) or digits (0-9).
The Output:
For each test case, output the two lines in the order they appear in the input. Output a third line indicating similarities and differences as described above. Finally, output a blank line after each case.
Sample:
int main()
{
int n;
// scan the integer for number of test cases
if(scanf("%d", &n) != 1) {
return 1;
}
//Loop through the test cases
for (int i = 0; i < n; i++)
{
char string1[1024], string2[1024], output[50];
//Scan first and second string
if(scanf("%s", string1) != 1) {
return 1;
}
if(scanf("%s", string2) != 1) {
return 1;
}
//Loop through the strings and compare them
for (int i = 0; string1[i] != '\0' || string2[i] != '\0'; i++)
{
//Convert to lowercase
string1[i] = tolower(string1[i]);
string2[i] = tolower(string2[i]);
//Compare
if (string1[i] == string2[i])
{
output[i] = '.';
} else {
output[i] = '*';
}
}
//Print the strings and the output.
printf("%s\n%s\n%s\n", string1, string2, output);
if(i + 1 < n) {
printf("\n");
}
}
return 0;
}
Maybe the problem is that when you have an input string in upper case ("ABCD") you print it in lowercase in the output ("abcd")?
The output string is never terminated, a '\0' should be added after the loop is over, otherwise printf would read over to the memory filled by previous test cases if their inputs were longer.
There is no great sense to declare the variable n as having the signed integer type int. Declare it at least as having type unsigned int.
unsigned int n;
// scan the integer for number of test cases
if(scanf("%u", &n) != 1) {
return 1;
}
The three character array should be declared as having 51 elements
char string1[51], string2[51], output[51];
The calls of scanf will look like
//Scan first and second string
if(scanf(" %50s", string1) != 1) {
return 1;
}
if(scanf(" %50s", string2) != 1) {
return 1;
}
Also you need to check that the entered strings have the same length as for example
if( strlen( string1) != strlen( string2 ) ) {
return 1;
}
This for loop
for (int i = 0; string1[i] != '\0' || string2[i] != '\0'; i++)
can invoke undefined behavior if the lengths of strings are not equal each other. If you will include the above shown if statement then the for loop can look the following way
size_t i = 0;
for ( ; string1[i] != '\0'; i++ )
These statements change the original strings
//Convert to lowercase
string1[i] = tolower(string1[i]);
string2[i] = tolower(string2[i]);
that you should not do. Just compare corresponding characters like
if (string1[i] == string2[i])
{
output[i] = '.';
} else {
output[i] = '*';
}
If you want to compare characters independent on their cases then write
if ( tolower( ( unsigned char )string1[i] ) == tolower( ( unsigned char )string2[i] ) )
{
output[i] = '.';
} else {
output[i] = '*';
}
After the for loop write
output[i] = '\0';
tp form a string in the array output.
It seems this if statement
if(i + 1 < n) {
printf("\n");
}
is redundant. Just output the new line character '\n'
putchar( '\n' );
after each test case.
Needlessly complicated. And, if the source strings contain any whitespace characters, scanf won't satisfy your needs. Below is both simpler and more robust.
Challenge assures no line more than 50 (or 500???) chars, so use only two small arrays.
Challenge is to also output LF after EVERY test case, so suppressing final one with special code is wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
void readAline( char *p, size_t n ) { // do or die
if( fgets( p, n, stdin ) == NULL )
exit( 1 );
}
int mmain() {
char buf[2][ 50 + 1 + 1 ]; // +2 = up to 50 + LF + '\0' from fgets()
readAline( buf[0], sizeof buf[0] );
int n = atoi( buf[0] );
while( n-- ) {
readAline( buf[0], sizeof buf[0] );
readAline( buf[1], sizeof buf[1] );
// can't be too careful when dealing with input
assert( strlen( buf[0] ) == strlen( buf[ 1 ] ) );
printf( "%s%s", buf[0], buf[1] ); // echo to stdout
// source data defined "up to 50 chars, so no test for '\0'
// recycle buf[0] for output
for( int i = 0; buf[0][i] != '\n'; i++ )
buf[0][i] = buf[0][i] == buf[1][i] ? '.' : '*';
puts( buf[0] ); // uses loaded LF and appended LF
}
return 0;
}
Demonstration
1
the cat sat on the mat
the fat cat in the vat
the cat sat on the mat // here is the echo
the fat cat in the vat
....*...*...*......*.. // here is the analysis
// blank line

Trying to break out of fgets while loop

#include <stdio.h>
#include <string.h>
int main(){
char c[20], result[50];
int bool = 0, count = 0, i;
while(fgets(c,20,stdin) != NULL){
int stringSize = strlen(c);
if(stringSize == 11){
int ascii = (int)(c[i]);
for(i = 0; i < stringSize; i++){
if(ascii >= 'A' && ascii <= 'Z'){
bool = 1;
}
}
}
}
if(bool == 1){
count++;
strcat(result,c);
}
printf("%d", count);
printf("%s",result);
}
Good morning, I am fairly new to programming, and I've spent quite a while Googling and searching around for this issue already, but I can't seem to wrap my head about it.
Basically I'm trying to filter an fgets so that it reads each string, and if they're capital letters, they're "valid". However, I can't even get the fgets to stop accepting more input.
Edit: The idea is to store in result every String that has 10 capital letters, and for the fgets while loop to break once the user gives no input ('\0')
If you are entering strings from the standard input stream then it is better to rewrite the condition of the while loop the following way
while( fgets(c,20,stdin) != NULL && c[0] != '\n' ){
In this case if the user just pressed the Enter key without entering a string then the loop stops its iterations.
Pay attention to that fgets can append the new line character '\n' to the entered string. You should remove it like
c[ strcspn( c, "\n" ) ] = '\0';
Then you could write
size_t n = strlen( c );
if ( n == 10 )
{
size_t i = 0;
while ( i != n && 'A' <= c[i] && c[i] <= 'Z' ) ++i;
bool = i == 10;
}
Pay attention to that it is a bad idea to use the name bool because such a name is introduced as a macro in the header <stdbool.h>.
Also it seems this if statement
if(bool == 1){
count++;
strcat(result,c);
}
must be within the while loop. And the array result must be initially initialized
char c[20], result[50] = { '\0' };

The answer outputs blanks

Program task -
Enter a string, display it word for word on the screen.
The problem is that if you type a lot of spaces between words, they will show up when you check. How can this be fixed?
#include <stdio.h>
int main()
{
int inw = 0, i = 0, count = 0;
char s[10000];
printf("Print string (max 10000 sb):\n");
gets(s);
while (s[i] != '\0') {
if (s[i] != ' ' && s[i] != '\t') {
putchar(s[i]);
}
else if (s[i] == ' ') {
printf("\n");
}
i++;
}
return 0;
}
Ugly, but this gets the job done. Just need a flag to keep track of whether or not you just printed a new line. Also cleaned up unused variables and changed to using fgets
#include <stdio.h>
#include <stdbool.h>
int main()
{
int i = 0;
char s[10000];
bool justPrintedNewline = false;
printf("Print string (max 10000 sb):\n");
fgets(s, sizeof s, stdin);
while (s[i] != '\0') {
if (s[i] != ' ' && s[i] != '\t') {
putchar(s[i]);
justPrintedNewline = false;
}
else if (s[i] == ' ' && justPrintedNewline == false) {
printf("\n");
justPrintedNewline = true;
}
i++;
}
return 0;
}
Demo
You did a great job in the algorithm just fix a little thing.
You can create a flag and after space you increase the flag to 1.
Then you will know you will print just one space.
After printing " " check for a char that isn't " " for update the flag to 0.
When the flag is 1 DONT print anything just wait for another valid char.
Take care,
Ori
Only print a line-feeed when starting a word and after all is done.
Change code to:
If a space
-- print a '\n' when the prior character is a non-white-space.
Else
-- if (prior character is white-space) print a '\n'
-- print it
char prior = 'a';
while (s[i]) {
char ch = s[i];
if (ch != ' ' && ch != '\t') {
if (prior == ' ' || prior == '\t') {
putchar('\n');
}
putchar(ch);
}
prior = ch;
i++;
}
putchar('\n');
There is a bit of a trick to it: use a second, inside loop to skip past spaces and another to print words. The outer loop should only terminate if you have reached the end of the string.
while (s[i] != '\0')
{
// skip all spaces
while ((s[i] != '\0') && isspace( s[i] )) ++i;
// print the word
while ((s[i] != '\0') && !isspace( s[i] ))
{
putchar( s[i] );
}
// print the newline after a word
putchar( '\n' );
}
By the way, gets() is a really, really dangerous function. It should never have been included in the language. You are OK to use it for a homework, but in reality you should use fgets().
char s[1000];
fgets( s, sizeof(s), stdin );
The fgets() function is a bit more fiddly to use than gets(), but the above snippet will work for you.
Your other option for solving this homework is to use scanf() to read a word at a time from user input, and print it each time through the loop. I’ll leave that to you to look up. Don’t forget to specify your max string length in your format specifier. For example, a 100 char array would be a maximum 99-character string, so you would use "%99s" as your format specifier.

Solving KNKING exercise 14, chapter 8. Reverse the words

I'm reading K.N.King C programming and I have an issue about it.
I'm solving project 5, chapter 12 which is modify project 14 from chapter 8 by using the pointer .
Project 8.14
Write a program that reverses the words in a sentence:
Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: you can't swallow a cage can you?
Hint: Use a loop to read
the characters one by one and store them in a one-dimensional char
array. Have the loop stop at a period, question mark, or exclamation
point (the "terminating character"), which is saved in a separate char
variable. Then use a second loop to search backward through the array
for the beginning of the last word. Print the last word, then search
backward for the next-to-last word. Repeat until the beginning of the
array is reached. Finally, print the terminating character.
#include <stdio.h>
#include <ctype.h>
#define N 100
int main()
{
char arr[N] = {0};
char *p, *q, mark = 0;
int c;
p = arr;
while((c = getchar()) != '\n' && p < arr + N)
{
if(c == '?' || c == '.' || c == '!')
{
mark = c;
break;
}
else
*p++ = c;
}
*p = '\0';
while(p >= arr)
{
while(*--p != ' ' && p != arr);
q = p == arr ? arr : p + 1;
while(*q != '\0' && *q != ' ')
{
printf("%c", *q++);
}
if(p >= arr)
printf(" ");
}
printf("\b%c", mark);
printf("\n");
}
the problem is if I enter enter a sentence "My name is jiyong!", expected output is "jiyong is name My!" but the output always has '\xxx'. How can I get rid off? and what is these '\xxx' things?
ran under Xcode 12.4
The second loop looks too complicated to me. You are required to scan the string backwards and print every word found, right? But you're not required to retain the whole sentence...?
So we can replace every space character with zero, thus terminating each word.
while((c = getchar()) != '\n' && p < arr + N)
{
if(c == '?' || c == '.' || c == '!')
{
mark = c;
break;
}
else
*p++ = (c == ' ') ? '\0' : c;
}
*p = '\0';
Then we can seek words backwards and print them as strings instead of iterating over their characters:
while(--p > arr) // all words except the first one
{
if(!*p && p[1]) //p[1] or *(p + 1)
printf("%s ", p+1);
}
printf("%s", arr); // the first word goes last
if(mark)
printf("%c", mark);
printf("\n");
I assumed p gets incremented at least once in the first loop, that is the input line is never empty. But that seems a valid assumption (although not very safe) as the input is defined as 'a sentence', so it should not be empty...

Scanf() function isn't taking string input

After taking test case inputs it does not waits for string input. I have tried fgets(); But, fgets() requires a newline from user which i think will not be accepted by online judge. So, whats the problem here ? Here is my code.
#include<stdio.h>
int main ()
{
int t, j;
int cnt = 0;
scanf("%d", &t);
while(t--)
{
cnt++;
int i, count = 0;
char s[101];
scanf("%[^\n]s", s);
for(i=0;s[i] != '\0'; i++)
{
if(s[i] == 'a' || s[i] == 'd' || s[i] == 'g' || s[i] == 'j' || s[i] == 'm' || s[i] == 'p' || s[i] == 't' || s[i] == 'w' || s[i] == ' ')
{
count += 1;
continue;
}
else if(s[i] == 'b' || s[i] == 'e' || s[i] == 'h' || s[i] == 'k' || s[i] == 'n' || s[i] == 'q' || s[i] == 'u' || s[i] == 'x')
{
count += 2;
continue;
}
else if(s[i] == 'c' || s[i] == 'f' || s[i] == 'i' || s[i] == 'l' || s[i] == 'o' || s[i] == 'r' || s[i] == 'v' || s[i] == 'y')
{
count += 3;
continue;
}
else if(s[i] == 's' || s[i] == 'z')
{
count += 4;
continue;
}
}
printf("Case #%d: %d\n", cnt, count);
}
return 0;
}
Change
scanf("%[^\n]s", s);
to
scanf(" %100[^\n]", s);
The space at the beginning makes it skip over any whitespace before the word. This is needed to allow it to read past the newline at the end of each line before scanning the next line.
100 ensures that it doesn't try to write past the end of the string.
You shouldn't have s at the end, because that will try to match a literal s in the input. [^\n] is not a modifier of the %s format operator, it's a completely different format operator.
It would help immensely if you had included a link to the specific question. Then we could advise if you had answered the question correctly.
For instance, what about capital letters, punctuation, etc.?
For instance, does the question guarantee that each input string will <= 100 characters, or is there a criteria that no more than the first 100 characters be used?
We cannot determine if the posted code is answering the question if we do not know what the question is.
Most I/O is very time/CPU cycles expensive, especially scanf() and printf()
Most online questions have the execution timed and exceeding the allowed time limit will cause the proposed answer (that you provide) to fail.
Appropriate 'fast' I/O functions are easily found by YOU by looking at the answers to prior questions. Here are a couple of fully functional examples to get you started:
#include <stdio.h>
void fastRead( size_t *a );
void fastWrite( size_t a );
inline void fastRead(size_t *a)
{
int c=0;
// note: 32 is space character
while (c<33) c=getchar_unlocked();
// initialize result value
*a=0;
// punctuation parens, etc are show stoppers
while (c>47 && c<58)
{
*a = (*a)*10 + (size_t)(c-48);
c=getchar_unlocked();
}
//printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
Most often (you may have to experiment a bit) the online code judging wants a newline output to stdout after each test case, including the last test case. This is usually accomplished by:
putchar_unlocked('\n');
When a value will never be less than 0, it is (usually) best to use size_t rather than int,
It is good programming practice to use variable names that indicate content or usage (or better, both).
code is MUCH more readable and understandable if
it is consistently indented
code blocks are separated by a single blank line
meaningful variable names are used
all 'distractor' code is eliminated
Putting all the above together results in:
#include <stdio.h> // putchar_unlocked(), getchar_unlocked()
void fastRead( size_t *a );
void fastWrite( size_t a );
inline void fastRead(size_t *a)
{
int c=0;
// note: 32 is space character
while (c<33) c=getchar_unlocked();
// initialize result value
*a=0;
// punctuation parens, etc are show stoppers
while (c>47 && c<58)
{
*a = (*a)*10 + (size_t)(c-48);
c=getchar_unlocked();
}
//printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
int main ( void )
{
size_t numTestCases;
fastRead( &numTestCases );
for( size_t testCase =1; testCase <= numTestCases; testCase++)
{
size_t count = 0;
int ch;
while( (ch = getchar_unlocked()) != '\n' )
{
if( ch == 'a'
|| ch == 'd'
|| ch == 'g'
|| ch == 'j'
|| ch == 'm'
|| ch == 'p'
|| ch == 't'
|| ch == 'w'
|| ch == ' ')
{
count += 1;
}
else if( ch == 'b'
|| ch == 'e'
|| ch == 'h'
|| ch == 'k'
|| ch == 'n'
|| ch == 'q'
|| ch == 'u'
|| ch == 'x')
{
count += 2;
}
else if( ch == 'c'
|| ch == 'f'
|| ch == 'i'
|| ch == 'l'
|| ch == 'o'
|| ch == 'r'
|| ch == 'v'
|| ch == 'y')
{
count += 3;
}
else if( ch == 's'
|| ch == 'z')
{
count += 4;
}
}
printf("Case #%lu: %lu\n", testCase, count);
putchar_unlocked( '\n' );
}
return 0;
}
The call to printf() could also be greatly sped up by using a series of calls to fastWrite() and putchar_unlocked()
Also, unless the question specifically asks for the superfluous characters being used in the call to printf() the code probably should say:
fastWrite( testCase );
putchar_unlocked( ' ' );
fastWrite( count );
putchar_unlocked( '\n' );
it is also highly desirable to list the parameters of the question at the top of your code. This both helps you and anyone else reading your code.
Here is a trivial example of such documentation:
/*
* criteria 1
* Using two characters: . (dot) and * (asterisk)
* print a frame-like pattern
*
* criteria 2
* You are given t - the number of test cases
*
* criteria 3
* for each of the test cases input two positive integers:
* l - the number of lines and
* c - the number of columns of a frame.
*
* criteria 4
* Use one line break in between successive patterns
*/
Given the latest information you have provided, here is the answer that I would suggest.
If it still does not pass the judge, at least you have a very solid base from which to experiment to determine the correct answer.
/*
* Cell phones have become an essential part of modern life.
* In addition to making voice calls,
* cell phones can be used to send text messages,
* which are known as SMS for short.
* Unlike computer keyboards, most cell phones have limited number of keys.
* To accommodate all alphabets, letters are compacted into single key.
* Therefore, to type certain characters,
* a key must be repeatedly pressed until that character is shown on the display
panel.
*
* In this problem we are interested in finding out the number of times
* keys on a cell phone must be pressed to type a particular message.
* In this problem we will assume that the key pad of our cell phone is arranged as follows.
* ---------------------
* |1 | abc | def |
* ---------------------
* | ghi | jkl | mno |
* ---------------------
* | pqrs | tuv | wxyz |
* ---------------------
* | | <SP>| |
* ---------------------
* In the above grid each cell represents one key.
* Here <SP> means a space.
* In order to type the letter `a', we must press that key once,
* however to type `b' the same key must be pressed twice
* and for `c' three times.
* In the same manner, one key press for `d',
* two for `e'
* and three for `f'.
* This is also applicable for the remaining keys and letters.
* Note that it takes a single press to type a space.
*
* Input
* The first line of input will be a positive integer T
* where T denotes the number of test cases.
* T lines will then follow each containing only spaces and lower case letters.
* Each line will contain at least 1 and at most 100 characters.
*
* Output
* For every case of input there will be one line of output.
* It will first contain the case number
* followed by the number of key presses required to type the message of that case.
* Look at the sample output for exact formatting.
*
* Sample Input
* 2
* welcome to ulab
* good luck and have fun
*
* Sample Output
*
* Case #1: 29
* Case #2: 41
*/
#include <stdio.h> // putchar_unlocked(), getchar_unlocked(), puts(), sprintf()
#include <string.h> // strcpy(), strcat()
#define MAX_OUTPUT_LEN 50
void fastRead( size_t *a );
void fastWrite( size_t a );
inline void fastRead(size_t *a)
{
int c=0;
// note: 32 is space character
while (c<33) c=getchar_unlocked();
// initialize result value
*a=0;
// punctuation parens, etc are show stoppers
while (c>47 && c<58)
{
*a = (*a)*10 + (size_t)(c-48);
c=getchar_unlocked();
}
//printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
const size_t keyPressCounts[] =
{
1, 2, 3, // a b c
1, 2, 3, // d e f
1, 2, 3, // g h i
1, 2, 3, // j k l
1, 2, 3, // m n o
1, 2, 3, 4,// p q r s
1, 2, 3, // t u v
1, 2, 3, 4 // w x y z
};
int main ( void )
{
size_t numTestCases;
fastRead( &numTestCases );
for( size_t testCase =1; testCase <= numTestCases; testCase++)
{
size_t keypresses = 0;
int ch;
while( (ch = getchar_unlocked()) != '\n' )
{
if( ' ' == ch )
keypresses += 1;
else
keypresses += keyPressCounts[ ch - 'a' ];
} // end while()
char outputLine[ MAX_OUTPUT_LEN ];
strcpy( outputLine, "Case #" );
sprintf( &outputLine[ strlen(outputLine) ], "%lu", testCase );
strcat( outputLine, ": " );
sprintf( &outputLine[ strlen(outputLine) ], "%lu", keypresses );
puts( outputLine );
} // end for()
return 0;
} // end function: main

Resources