Solving KNKING exercise 14, chapter 8. Reverse the words - c

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...

Related

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.

fgets() and scanf() not working properly in unison. Buffer problem encountered

My assignment: -
Write a program that replaces the occurence of a given character (say
c) in a primary string (say PS) with another string (say s).
Input: The first line contains the primary string (PS) The next line
contains a character (c) The next line contains a string (s)
Output: Print the string PS with every occurence of c replaced by s.
Test case 1: -
Input: -
abcxy
b
mf
Expected output: -
amfcxy
Test case 2: -
Input: -
Al#bal#20owL
l
LL
Expected output: -
ALL#baLL#20owL
My code below: -
#include <stdio.h>
#include <stdlib.h>
int main() {
char PS[101];
char c;
char S[11];
fgets(PS, 101, stdin); //PS value input.
scanf("%c", &c);
if (c == '\n' || c == '\0') {
scanf("%c", &c); //Clearing the buffer. I want the real value of 'c' from STDIN not '\n'
}
fgets(S, 11, stdin); //S value input.
int i = 0;
while (PS[i] != '\0') { //Removing the '\n' from PS
if (PS[i] == '\n') {
PS[i] = '\0';
break;
}
i++;
}
i = i - 1; //i now holds the value of the size of the string PS (excluding '\0')
int j = 0;
while (S[j] != '\0') {
if (S[j] == '\n') {
S[j] = '\0';
break;
}
j++;
}
j = j - 1; //j now holds the value of the size of the string S (excluding '\0')
int k = 0; //work as an initializer
int move = 0; //work as an initializer.
while (PS[k] != '\0') { //This loops checks the whole array for the same character mentioned in char 'c'
if (PS[k] == c) {
for (move = i; move > k; move --) { //This loop advances the all the characters in PS by '(j - 1)' steps to make space for string S characters.
PS[move + (j - 1)] = PS[move];
}
for (move = 0; move < j; move++) { //This loop adds all the characters of string S into string PS at the relevant place.
PS[k + move] = S[move];
}
i = i + (j - 1); // 'i' now holds the new value of size of string PS after adding all the characters of string S.
}
k++;
}
puts(PS);
return 0;
}
Now the problem is that the code is not taking the input for string S.
After inputting first 2 inputs, it executes and gives a gibberish answer. I cannot figure out the bug, but what I do know is that there is some issue related to the buffer in C. Please help.
Edit: -
Thanks to #WeatherVane I have now edited the code with this: -
scanf("%c", &c);
if (c == '\n' || c == '\0') {
scanf("%c", &c); //Clearing the buffer. I want the real value of 'c' from STDIN not '\n'
}
char x;
x = getchar(); //New addition. It eats the '\n' after scanf().
fgets(S, 11, stdin); //S value input.
Now my code is working fine but the output is still not correct. It is sometimes failing to copy the last char from string S or giving me gibberish output.
The problem with the code was: -
i = i - 1; //i now holds the value of the size of the string PS (excluding '\0')
j = j - 1; //j now holds the value of the size of the string S (excluding '\0')
The value of i and j are the true values of the size of string PS and string S; not i = i - 1 and j = j - 1.
Lesson learnt from this assignment: -
scanf() does not treat '\n' in any way. It WILL be left in the
buffer.
If possible use fgets and then remove '\n' from your respective array/pointer.
Be extra careful of your C buffer when dealing with chars and strings.
The final correct code is: -
#include <stdio.h>
#include <stdlib.h>
int main()
{
char PS[101];
char c;
char S[11];
fgets(PS, 101, stdin); //PS value input.
scanf("%c", &c);
if(c == '\n' || c == '\0')
{
scanf("%c", &c); //Clearing the buffer. I want the real value of 'c' from STDIN not '\n'
}
char x;
x = getchar(); //New addition. It eats the '\n' after scanf().
fgets(S, 11, stdin); //S value input.
int i = 0;
while(PS[i] != '\0') //Removing the '\n' from PS
{
if(PS[i] == '\n')
{
PS[i] = '\0';
break;
}
i++;
}
i = i; //i now holds the value of the size of the string PS (excluding '\0')
int j = 0;
while(S[j] != '\0')
{
if(S[j] == '\n')
{
S[j] = '\0';
break;
}
j++;
}
j = j; //j now holds the value of the size of the string S (excluding '\0')
int k = 0; //work as an initializer
int move = 0; //work as an initializer.
while(PS[k] != '\0') //This loops checks the whole array for the same character mentioned in char 'c'
{
if(PS[k] == c)
{
for(move = i; move > k; move --) //This loop advances the all the characters in PS by '(j - 1)' steps to make space for string S characters.
{
PS[move + (j - 1)] = PS[move];
}
for(move = 0; move < j; move++) //This loop adds all the characters of string S into string PS at the relevant place.
{
PS[k + move] = S[move];
}
i = i + (j - 1); // 'i' now holds the new value of size of string PS after adding all the characters of string S.
}
k++;
}
puts(PS);
return 0;
}
Warning: -
The above code is very unoptimised and unreadable. Do not use it for
long term projects. It just "works".
Any suggestions for improvements of the above code are welcomed in
the comments.
Further necessary reading material recommended if you face any issue regarding C buffer in the future: -
Read 1
Read 2

Encryption with swapping letters in C

I need to write a program that reads from the input a sentence terminated by a new line. The program should write an encryption of the sentence in a way that the letter 'a' is swapped with 'z', 'b' with 'y' and so on. I am not supposed to use arrays, that is why I can't find a solution for this problem.
This is my code:
#include<stdio.h>
int main() {
char alphabet, temp;
while( scanf("%c", &alphabet) != '\n') {
for(char i ='a', j='z'; i <= 'z', j>='a'; i++, j--) {
if(alphabet == i) {
temp = j;
}
}
printf("%c", temp);
}
return 0;
}
When I input: abc as an output I get zyxxxxxxxxxxxxxxxxxxxxxxxxx(an infinite number of x).
So to sum up:
Input:abc. Output: zyxxxxx(infinite number of x).
You messed up the return value of scanf:
while( scanf("%c", &alphabet) != '\n'){
You want to stop the loop when the entered character (in alphabet) is a line break.
But you test the return value of scanf which will never be '\n' as it returns the number of converted fields.
You could try like this:
while( scanf("%c", &alphabet) == 1 && alphabet != '\n'){
Compile your code with warnings enabled (e.g. Wall flag)! This:
for(char i ='a', j='z'; i <= 'z', j>='a'; i++, j--)
should give:
warning: left-hand operand of comma expression has no effect [-Wunused-value]
You need to use the logical AND operator && and not a comma between the two comparissons.
Moreover, use getchar() instead, like this:
#include<stdio.h>
int main() {
char temp;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
for(char i ='a', j='z'; i <= 'z'&& j>='a'; i++, j--){
if(ch == i){
temp = j;
}
}
if(ch <= 'z'&& ch >= 'a') // do not print if 'ch' is a digit for example
printf("%c", temp);
}
return 0;
}
Output:
zyx
If you have to use scanf(), then try reading into alphabet, check the return value of scanf, and compare to newline, like this:
while(scanf("%c", &alphabet) != 0 && alphabet != '\n')

Issue with String position appending C program

I am trying to write program for piglatin. I was not getting the output what I am expecting.
take the first letter of a “word” and appending that letter to the end of the word with “ay” added to the end as well.
Input : Darrin, what are you doing with 500 and 100?
Output: arrin, hatway reaay ouyay oingday ithway 500 ndaay 100?
Expected Output: arrinday,hatway reay ouyay oingday ithway 500 nday 100?
What's wrong with output : First word not appended with ay
Since I am appending 'ay', I need eliminate the extra 'a' if the word starts with a or end's with 'a'. I just need add ay at the end instead of first letter + ay. For example: Input is Alex and allen are 500 Output should be lexay nday llenay
Also if the starting letter is not alphabet then we should return the same word.
Please help me to solve this
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
static char inputBuffer[100];
static char outputBuffer[100];
void translate (void)
{
char bufferValue;
char firstLetter;
int j = 0, k = 0, m = 0;
printf("\n");
while (j < (sizeof(inputBuffer) - 1))
{
bufferValue = inputBuffer[j];
if (((bufferValue >= 'A') && (bufferValue <= 'Z')) || ((bufferValue >= 'a') && (bufferValue <= 'z')))
{
if (j == 0)
{
firstLetter = bufferValue;
}
else if (inputBuffer[j-1] == ' ')
{
firstLetter = bufferValue;
}
else
{
printf("%c", bufferValue);
outputBuffer[m] = bufferValue; m++;
}
}
else if ((bufferValue == ' ') && !(
((inputBuffer[j-1] < 'A') ||
((inputBuffer[j-1] > 'Z') && (inputBuffer[j-1] < 'a')) ||
(inputBuffer[j-1] > 'z'))))
{
printf("%cay%c", firstLetter, bufferValue);
outputBuffer[m] = firstLetter; m++;
outputBuffer[m] = 'a'; m++;
outputBuffer[m] = 'y'; m++;
outputBuffer[m] = bufferValue; m++;
firstLetter = ' ';
}
else
{
printf("%c", bufferValue);
outputBuffer[m] = bufferValue; m++;
}
j++;
}
printf("\n final output: %s",outputBuffer);
return;
}
int main(void)
{
printf("enter the string\t");
fflush(stdin);
gets(inputBuffer);
printf ("\nInput buffer contents: %s", inputBuffer);
translate();
return 0;
}
First word not appended with ay
The problem is just not that only the first word is not being appended by first letter and ay, but whenever you have some non alphabet character at the end of a word (digits/special characters, except space), ay will not be appended to that word.
For example, try this input:
Darrin, what, are you doing with 500 and 100?
You'll get the output:
arrin, hat, reaay ouyay oingday ithway 500 ndaay 100?
So mainly, the problem is in the last else you have:
else
{
printf("%c", bufferValue);
outputBuffer[m] = bufferValue; m++;
}
See, when , comes immediately after a word, the control comes to this else and it just adds the , as it is, it does not append the firstLetter and ay.
But you can't always append firstLetter and ay in this else, you'll have to come up with some kind of condition, so you could separate the 500 and Darrin,, cause 500 will also go through this else statement.
Maybe, you could try checking if firstLetter is an alphabet or not, if it is, then append the firstLetter and ay, otherwise not.
else
{
if ((firstLetter >= 'a' && firstLetter <= 'z') || (firstLetter >= 'A' && firstLetter <= 'Z'))
printf("%cay", firstLetter);
outputBuffer[m] = firstLetter; m++;
outputBuffer[m] = 'a'; m++;
outputBuffer[m] = 'y'; m++;
firstLetter = ' ';
}
printf("%c", bufferValue);
outputBuffer[m] = bufferValue; m++;
}
But this will still not process the words like 0abcdef,, which do have alphabets in it, but start with some non-alphabet character, so that's your call, if you want to put them to the numbers category (like 500), to leave them as they are, or to process them.
Here is the working example.
P.S. I've made some other changes too (which don't affect your output), but the major change was what I explained (which does).
EDIT:
From the comments below:
If the word starts with Vowel(a,e,i,o,u) then just add y else first letter + ay
You can write a function in your program called isVowel to check if some character is vowel or not:
int isVowel(char c)
{
c = tolower(c);
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
return 1;
return 0;
}
Now, you're adding ay at two places in your program:
In the else if and the last else:
outputBuffer[m] = firstLetter; m++;
outputBuffer[m] = 'a'; m++;
outputBuffer[m] = 'y'; m++;
firstLetter = ' ';
So, you can add an if at the statements outputBuffer[m] = 'a'; m++; to only add this a if the firstLetter is not a vowel:
outputBuffer[m] = firstLetter; m++;
if (!isVowel(firstLetter))
{
outputBuffer[m] = 'a';
m++;
}
outputBuffer[m] = 'y'; m++;
firstLetter = ' ';
change this at both places i.e. in the else if and else, and you'll be done.
I've updated the code on ideone
The real problem is that you didn't see the forest through the trees which made the implementation awful to read. To add insult to injury, you decided to break the basic rules of code locality (not using globals unless necessary) and DRY (functions to tell if a charater is a letter exist in the standard library of any language I can think of, don't reimplement it), which made it pretty much irrecoverable as far as maintenance is concerned.
Now, let's read the task description again:
take the first letter of a “word” and appending that letter to the end of the word with “ay” added to the end as well.
Notice what already stands out because of quoting: word.
So, I'd divide the implementation into two distinct tasks:
Iterate through a sentence word by word.
Once you can reliably identify words, do the piglatin thing.
The end result of might look like this:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void piglatinize(const char* in)
{
static const char* SEP = " .,?"; // word separators
// Iterate input by words
const char *sep = NULL, *word = NULL, *end = in;
while (sep = end, // separators from previous word end
word = &end[strspn(end, SEP)], // start of word
end = &word[strcspn(word, SEP)], // end of word
*sep) // iterate until we hit terminating zero character
{
int wordlen = (int)(end - word);
int seplen = (int)(word - sep);
if (wordlen > 0 && isalpha(word[0])) // word starts with a letter, pig it!
{
char firstletter = tolower(word[0]);
const char* suffix = (firstletter == 'a') ? "y" : "ay";
printf("%.*s%.*s%c%s",
seplen, sep, // separators from previous word
wordlen - 1, &word[1], // word without first letter
firstletter, suffix);
}
else // not a real word, just print unchanged
{
printf("%.*s%.*s", seplen, sep, wordlen, word);
}
}
}
int main()
{
piglatinize("Darrin, what are you doing with 500 and 100?");
}
I admit the while loop continuation condition is a handful. If you have trouble understanding this example you might want to read on strspn (and its opposite strcspn) and the comma operator.

Only print words that start with a specified letter out of a string in C language

I need to write a function that will print words that start with specified letter inside a string.. my problem is that once i try to print a words, the function never stop.
Here is the code: (printWords is the functions, printWord is a helper)
#include <stdio.h>
#include <string.h>
typedef char string[50];
void printWord(int *index, string sentence)
{
while (sentence[*index] != ' ' || sentence[*index] != '\0')
{
printf("%c", sentence[*index]);
*index += 1;
}
}
void printWords(char letter, string sentence)
{
int i = 0, *iPtr = &i;
if (sentence[0] == letter || sentence[0] == letter + 32)
printWord(iPtr, sentence);
for (; sentence[i] != '\0'; i++)
if ((sentence[i] == ' ' && sentence[i+1] == letter) || (sentence[i] == ' ' && sentence[i+1] == letter + 32))
printWord(iPtr, sentence);
}
void main()
{
char ex1_letter;
int menu;
string ex1_sentence;
printf("\n\nPlease enter a string: ");
gets(ex1_sentence);
printf("\nPlease enter a letter: ");
scanf("%c", &ex1_letter);
printWords(ex1_letter, ex1_sentence);
}
The condition in the loop never seems to happen and i just don't know why..
Any help would be appreciated!
Your main error is using || insted of && in printWord. With || the condition will always be true since the character will always not be either space or the null character.
Some other points:
It's more portable for main to return an int (and have a return 0; at the end).
Use of gets is discouraged as it allows buffer overruns. fgets is more secure, but beware that it leaves the newline character at the end of the string.
Don't do things like letter + 32. Instead, use the functions in ctype.h. In this case, use tolower or toupper.
Instead of passing i as a pointer, just pass it as an int and return the changed value.
Don't use printf and scanf to print/scan a single character. Instead use putchar and getchar.
Use ++i instead of i += 1.
Your typedef just obscures things. If the declaration of (e.g.) printWords is void printWords(char letter, char *sentence) then a C programmer knows what's going on right away without having to know what string is. The typedef really adds nothing.
In your printWord method:
while (sentence[*index] != ' ' || sentence[*index] != '\0')
This conditions will always be true. Change it to &&: print as long it is not a space AND not the end of string, like this:
while (sentence[*index] != ' ' && sentence[*index] != '\0')

Resources