Related
I'm trying to write a program (in C) where the input is reversed and printed in reverse line by line. For the most part, the code actually does just that. The trouble is that for some (most) of my input, I will get a random character or an extra newline in between my input and my output in the console.
For example, I start the program, type "testing" into the console, and get "gnitseT" back after hitting enter. This has happened successfully and is what I expect. It looks like this:
Testing
gnitseT
But then when I type "Hello" into the console, it looks like this:
Hello
g (unexpected)
olleH
Or if I type "running" into the console, instead of getting an unexpected "g" in between my input and output lines, I get an extra newline.
Running
newline here
extra newline here (unexpected)
gninnuR
#include <stdio.h>
void reverse(int length, char s[])
{
int i;
for (i = length; i >= 0; i--)
{
printf("%c", s[i]);
}
printf("\n");
}
int main(void)
{
char smain[2000];
int c;
int i;
i = 0;
while ((c = getchar()) != EOF)
{
smain[i] = c;
i++;
if (c == '\n')
{
reverse(i, smain);
i = 0;
}
}
return 0;
}
The expected behavior is for the program to output into the console the reversed input after the enter key is pressed.
Sometimes, especially at the very beginning of the program, it will work perfectly.
Then, it starts giving me a random character in between my input and output, or it starts giving me an extra newline.
I would like to have it so that it just prints the input in reverse order without any unexpected odd characters showing up in between the input and the output.
Thanks for any help.
Your immediate problem is you are reading and attempting to print one character past the end of the characters stored in your array with
for (i = length; i >= 0; i--) {
printf("%c", s[i]);
}
Why? You add length characters to smain in main(). In C, arrays are zero-based. The characters in your string are from 0 -> length-1 (the nul-character in a string is located at s[length], but here you never add a nul-terminating character, so the value at that index is simply indeterminate). If the element has not been initialized (which it will not be on your first word or any subsequent word equal to or longer than your longest word entered at that time) Undefined Behavior results since you are attempting to read and print an indeterminate value from an uninitialized element in array. How your terminal will output the indeterminate is undefined -- and may well result in a G being printed.
To correct the problem, loop for (i = length - 1; i >= 0; i++) or very simply:
while (length--)
printf ("%c", s[length]);
putchar ('\n'); /* don't printf a single-character */
(note: don't call the variadic printf function to output a single-character, that is what putchar() is for)
Putting it altogether and fixing your logic so you don't add and print the '\n' as part of every word you are reversing, you could do:
#include <stdio.h>
#define MAXC 2048 /* if you need a constant, #define one (or more) */
void reverse(int length, char s[])
{
while (length--)
printf ("%c", s[length]);
putchar ('\n'); /* don't printf a single-character */
}
int main (void) {
char smain[MAXC];
int c, i = 0;
while ((c = getchar()) != EOF) {
if (c == '\n') {
reverse(i, smain);
i = 0;
}
else
smain[i++] = c;
}
if (i) /* protect against file with no POSIX end-of-file */
reverse (i, smain);
return 0;
}
(note: the if {...} else {...} logic to prevent adding the '\n')
Example Use/Output
$ printf "Hello\nGoodbye\n" | ./bin/prnrevlines
olleH
eybdooG
Which will work just as well without the POSIX eof, e.g.
$ printf "Hello\nGoodbye" | ./bin/prnrevlines
olleH
eybdooG
on line 29
++i;
this means "i" now have length+1 so, you have been out of the string, you can change the program to :
#include <stdio.h>
void reverse(int length, char s[])
{
int i;
for (i = length; i >= 0; i--)
{
printf("%c", s[i]);
}
printf("\n");
}
int main(void)
{
char smain[2000];
int c;
int i;
i = 0;
while ((c = getchar()) != EOF)
{
smain[i] = c;
if (c == '\n')
{
reverse(i, smain);
i = 0;
}
else i++;
}
return 0;
}
I'm having trouble printing each word in a separate line from an input string in C. The question from the assignment I'm doing states:
Take a sentence as input and print its words in separate lines.
My Code:
#include<stdio.h>
int main()
{
int i;
char s[100];
scanf("%s", s);
for(i=0; s[i]!='\0'; i++)
{
printf("%c", s[i]);
if(s[i]==' ')
{
printf("\n");
}
}
}
Any help would be appreciated.
In your code,
printf("%s", s[i]);
is wrong. Change it to
printf("%c", s[i]);
as, you're trying to print a char value. The conversion specifier for a char is %c.
Note: Always remember, using wrong conversion specifier will lead to undefined behaviour.
Also, while scan()-ing with %s, you cannot read the whole space-delimited input as a single string. From the man page,
%s
Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.
You need to use fgets() to do the job.
That said,
Indent your code properly, make it human-readable.
Chnage scanf("%s", s); to scanf("99%s", s); to avoid possible buffer overflow by putting longer input string than 99 chars.
the proper signature for main() is int main(void).
Rookie, using line-oriented input like fgets or getline is, in general, the proper way to read a line of text. However, when doing simple splitting on a single character, reading a character at a time can be advantageous.
In your case if your task is to read a sentence up to 100 characters and print the words of the sentence out on separate lines, then there is no reason to read the sentence into an array and store the words. You can simply read/print each character until a space is read, then print a newline instead of the space. The reading/printing continues until you reach 100 chars, encounter a newline or EOF:
#include <stdio.h>
#define MAXC 100
int main(void) {
int c = 0;
size_t n = 0;
printf ("\n Enter a sentence.\n\n input: ");
/* read up to 100 characters from stdin, print each word on a line */
while (n < MAXC && (c = getchar ()) != EOF && c != '\n')
{
if (c == ' ')
printf ("\n");
else
printf ("%c", c);
n++;
}
printf ("\n");
if (n == MAXC) /* read and discard remaining chars in stdin */
while ((c = getchar ()) != '\n' && c != EOF);
return 0;
}
Use/Output
$ ./bin/getchar_print_nl_space
Enter a sentence.
input: This is a sentence to split into words.
This
is
a
sentence
to
split
into
words.
Note: if you were going to store all characters, up to 100 (meaning 99 chars and 1 null-terminator), you would need to adjust the length check to n < MAXC - 1 and then null-terminate the array:
char s[MAXC] = {0};
/* read up to 99 characters from stdin into s */
while (n < MAXC - 1 && (c = getchar ()) != EOF && c != '\n')
s[n++] = c;
s[n] = '\0'; /* null-terminate after last character */
if (n == MAXC - 1) /* read and discard remaining chars in stdin */
while ((c = getchar ()) != '\n' && c != EOF);
You would then repeat the logic checking for a space and printing a newline in a for loop:
for (c = 0; c < n; c++)
if (s[c] == ' ')
printf ("\n");
else
printf ("%c", s[c]);
Understanding both manner of input, character-oriented input and line-oriented input will save you time allowing you to match the correct tool to the situation. Here, there is no "more correct" or "less correct" approach, just different ways of doing it.
I think one more way to do this work in a better way is as following.
#include <stdio.h>
#include <string.h>
#define MAX_CHAR 100
int main() {
char s[100],*c;
int i = 0;
scanf("%[^\n]", s);
//Write your logic to print the tokens of the sentence here.
for ( c = s; *c != (int)NULL; c++){
if ( *c == ' '){
*c = '\n';
}
}
printf("%s",s);
return 0;
}
Below code is the answer.
Program also calculates number of space/char and new line.
http://cprograming-char-operation.blogspot.com/2018/07/for-given-statement-print-word-in-each.html
/* Program 1_12 */
/* Count number of line, space and char */
/* Replace a char with specific newline */
/* Add blank space in first input */
#include<stdio.h>
int main()
{
int c,nl,nc,ns,nt;
nl=nc=ns=nt=0;
int d,r, prevd, prevr;
printf("Enter which char to replace :: ");
/* prev is stored before of \n */
while((d = getchar()) != '\n' && (prevd = d));
d = prevd;
printf("Enter word below \n");
while((c=getchar()) != EOF)
{
++nc;
if(c==' ')
++ns;
if(c=='\n')
++nl;
if(c=='\t')
++nt;
/* Replace a char with A */
if(c==d)
putchar('\n');
else
putchar(c);
}
printf("total char=%2d, newline=%2d, space=%2d tabs=%2d\n",nc,nl,ns,nt);
return 0;
}
/* Written by: Prakash Katudia <prakash.katudia#gmail.com> */
gcc ./my_code.c
./a.out
Enter which char to replace :: #space#
Enter word below
hello how are you
hello
how
are
you
#include<stdio.h>
#include<string.h>
int main()
{
char a[1000];
int i,len;
scanf("%[^\n]s",a);
len=strlen(a);
for(i=0;i<len;i++)
{
if(a[i] !=' ')
{
printf("%c", a[i]);
printf("\n");
}
}
}
In this program I have taken a dimensional character array of size[3][4],
as long as I enter a 3 characters for each row it will work well.
For example: if I enter abc abd abd I get the same output but if i enter more letters in the first or second or 3rd row I get an error.
How should I check for null character in 2 dimensional?
# include <stdio.h>
#include <conio.h>
# include <ctype.h>
void main()
{
int i=0;
char name[3][4];
printf("\n enter the names \n");
for(i=0;i<3;i++)
{
scanf( "%s",name[i]);
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
getch();
}
As pointed out by #SouravGhosh, you can limit your scanf with "%3s", but the problem is still there if you don't flush stdin on each iteration.
You can do this:
printf("\n enter the names \n");
for(i = 0; i < 3; i++) {
int c;
scanf("%3s", name[i]);
while ((c = fgetc(stdin)) != '\n' && c != EOF); /* Flush stdin */
}
How should I chk for null character in 2 dimensional ... [something has eaten the rest part, I guess]
You don't need to, at least not in current context.
The problem is in your approach of allocating memory and putting input into it. Your code has
char name[3][4];
if you enter more that three chars, you'll be overwriting the boundary of allocated memory [considering the space of \0]. You've to limit your scanf() using
scanf("%3s",name[i]);
Note:
change void main() to int main(). add a return 0 at the end.
always check the return value of scanf() to ensure proper input.
EDIT:
As for the logical part, you need to eat up the remainings of the input words to start scanning from the beginning of the next word.
Check the below code [Under Linux, so removed conio.h and getch()]
# include <stdio.h>
# include <ctype.h>
int main()
{
int i=0; char name[3][4];
int c = 0;
printf("\n enter the names \n");
for(i=0;i < 3;i++)
{
scanf( "%3s",name[i]);
while(1) // loop to eat up the rest of unwanted input
{ // upto a ' ' or `\n` or `EOF`, whichever is earlier
c = getchar();
if (c == ' ' || c == '\n' || c == EOF) break;
}
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
return 0;
}
(Cringing after reading the answers to date.)
First, state the problem clearly. You want to read a line from stdin, and extract three short whitespace separated strings. The stored strings are NUL terminated and at most three characters (excluding the NUL).
#include <stdio.h>
void main(int, char**) {
char name[3][4];
printf("\n enter the names \n");
{
// Read tbe line of input text.
char line[80];
if (0 == fgets(line, sizeof(line), stdin)) {
printf("Nothing read!\n");
return 1;
}
int n_line = strlen(line);
if ('\n' != line[n_line - 1]) {
printf("Input too long!\n");
return 2;
}
// Parse out the three values.
int v = sscanf(line, "%3s %3s %3s", name[0], name[1], name[2]);
if (3 != v) {
printf("Too few values!\n");
return 3;
}
}
// We now have the three values, with errors checked.
printf("you entered these names\n%s\n%s\n%s\n",
name[0], name[1], name[2]
);
return 0;
}
you might consider something on the order of scanf( "%3s%*s",name[i]);
which should, if I recall correctly, take the first three characters (up to a whitespace) into name, and then ignore anything else up to the next white space. This will cover your long entries and it does not care what the white space is.
This is not a perfect answer as it will probably eat the middle entry of A B C if single or double character entries are mode. strtok, will separate a line into useful bits and you can then take substrings of the bits into your name[] fields.
Perhaps figuring out the entire requirement before writing code would be the first step in the process.
I wrote the following code to accept characters from user and enter into an array till he inputs a free space (' ') or a line \n. But code is not functioning. As in, when space bar or return key is pressed in the input, my computer is still accepting values without exiting the loop.
char X[99];
printf ("Type the string without spaces\n");
for (i=0;i<99;i++) {
scanf ("%c",&m);
if(m!=' '&&m!='\n')
X[i]=m;
else i=99;
}
Please explain the error.
First the issue: the default tty mode is canonical, meaning input is made available line by line (see man termios)
Once you fix that, you can use getchar() or read() to get one character at a time. The tty setting, example straight out of the man page of termios .
#include <stdio.h>
#include <termios.h>
int ttySetNoncanonical(int fd, struct termios *prev)
{
struct termios t;
if (tcgetattr(fd, &t) == -1)
return -1;
if (prev != NULL)
*prev = t;
t.c_lflag &= ~ (ICANON);
t.c_cc[VMIN] = 1; // 1-char at a go
t.c_cc[VTIME] = 0; // blocking mode
if (tcsetattr(fd, TCSAFLUSH, &t) == -1)
return -1;
return 0;
}
void main(void) {
printf ("\nType the string without spaces\n");
ttySetNoncanonical(0,NULL); // set to non-canonical mode
char X[1000];
int m, ec=0;
int i;
X[0] = 0;
for (i=0;i<1000;i++) {
//ec = read(0,X+i,1); // read one char at a time
m = getchar();
if(m == EOF || m==' ' || m=='\n') {
X[i] = 0;
break;
}
X[i] = m;
}
printf("You entered %s. Bye.\n\n", X);
}
HTH. You might want to check the boundary condition, in case your user typed in 1000 characters. It works for me on a GNU Linux.
use getch(), scanf() will not work that way.
it would be something like :
for(i=0;i<99;i++)
{
char ch=getch();
if(m!=' ' && m!='\n' && m!='\r')
X[i]=m;
else i=99;
printf("%c",ch);
}
The scanf function reads and ignores any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters). So, instead of
scanf("%c",&m);
use
m = getchar();
The function int getchar ( void ); gets character from stdin, returns the next character from the standard input (stdin). It is equivalent to calling getc with stdin as argument.
Also, the condition should use logical-AND as in:
if(m!=' '&& m!='\n')
Also, outside the loop, write,
X[i] = '\0';
Lets look into the if condition
if(m!=' '||m!='\n')
1. When m is space m=' ' (i.e. ASCII value 32)
m=' '
As per your if condition (Cond1 || Cond2), Cond1 will fail and o/p will be 0 but Cond2 will be TRUE, because it is not ' '.
if(FALSE || TRUE)
will be if(TRUE).
When your input is newline (i.e ASCII value 10).
m='\n'
Here Cond1 will be TRUE because it is not SPACE, due to this it will not check the second condition as per C. and will execute the if(TRUE) statement.
Please try to code it by yourself.... It will help you to clear few C doubts and u will get to know how || and && condition works.
Better to use getchar() instead of scanf in here as you read character by character. Usually we use scanf for get strings as input.
Using the logical operators: && (AND) operator checks for one condition to be false, while or || (OR) operator checks for one condition to be true. So if you use && operator, it checks whether it is a space, and if not, it returns false, without even checking the second condition(EOF). But if you use || operator, as used below, it checks for both cases. Check for more details in operators here
You also have to increment the counter (i) after adding an item to the array (Inside the if) as if you don't, it will continuously add items to the same place of the array, which means you will lost the precious inputs.
So, here's my code:
char X[99];
char m;
printf ("Type the string without spaces\n");
for (i=0;i<99;i++) {
m = getchar();
if(m == ' ' || m=='\n') {
X[i]=m;
i++;
}
else i=99;
}
With the function getch(); it ends if your pressing space or enter!
#include <stdio.h>
int main(void) {
char m, X[99];
int i;
printf("Type the string without spaces\n");
for (i = 0; i < 99; i++) {
m = getch();
if (m == ' ' || m == '\n' || m == '\r')
i=100;
else
X[i] = m;
printf("%c", m);
}
}
try this
#include <stdio.h>
int main(){
int i;
char m, X[99];
printf("Type the string without spaces\n");
for (i=0;i<98;i++){//98 --> sizeof(X) -1
scanf("%c",&m);
if(m!=' ' && m!='\n')
X[i] = m;
else
break;
}
X[i] = '\0';
puts(X);
return 0;
}
Here's a working code:
#include <stdio.h>
int main ()
{
char x[100] = {0};
char m;
int i, j;
printf ("Type:\n");
for (i=0; i<99; i++) {
m = getchar();
getchar();
if ((m != ' ') && (m != '\n')) {
x[i] = m;
} else {
printf ("Breaking.");
break;
}
}
printf ("\n");
for (j=0; j<i; j++)
printf ("%c\n", x[j]);
return 0;
}
Here I have used an extra getchar() to consume the newline used to enter the character m. And so (please note) you will also need to enter a newline after a space (' ') and a newline ('\n') to enter and store these in m and compare them in the next lines.
First error, as everyone has pointed out is the logical operator in the if() statement. It should be
if(m!=' ' && m!='\n')
As you want to check if the entered character is neither a (space) nor a \n, so you have to use the && operator.
Next, the error you are getting is because of something called the trailing character. When you enter a letter and press enter (at the point where your scanf("%c",&m) is asking for input). That letter gets stored in the variable m, but the newline character \n caused by the enter pressed is still in the stdin. That character is read by the scanf("%c",&m) of the next iteration of the for loop, thus the loop exits.
What you need to do is consume that trailing character before the next scanf() is executed. for that you need a getchar() which does this job. So now your code becomes something like this..
#include<stdio.h>
int main()
{
char X[99];
char m;
int i;
printf("Type the string without spaces\n");
for (i=0;i<99;i++)
{
scanf("%c",&m);
if(m!=' ' && m!='\n')
{
X[i]=m;
getchar(); // this statement is consuming the left out trailing character
}
else
i=99;
}
printf("%s",X);
}
Now, the program works exactly as you want.
Ok, i'm a student in his first experiences with programmaing so be kind ;) this is the correct code to print "n" times a string on screen...
#include <stdio.h>
#include <string.h>
#define MAX 80+1+1 /* 80+\n+\0 */
int main(void)
{
char message[MAX];
int i, n;
/* input phase */
printf("Input message: ");
i = 0;
do {
scanf("%c", &message[i]);
} while (message[i++] != '\n');
message[i] = '\0';
printf("Number of repetitions: ");
scanf("%d", &n);
/* output phase */
for (i=0; i<n; i++) {
printf("%s", message);
}
return 0;
}
why in the do-while form he needs to check if message[i++] != '\n' and not just message[i] != '\n'??
The proper way to write that input loop is, in my opinion, something along the lines of:
fgets(message, sizeof message, stdin);
in other words, don't use a character-by-character loop, just use the standard library's function that reads a string terminated by newline and be done.
The do { ... } while(...) loop in your code reads characters one at a time and stores them in message. The index of the next character is one more that the index of the previous character, that's why we should increase index variable i after the current character is stored. The algorithm is:
Read the next character and store it in message[i].
If this character is '\n', exit.
Increase i and goto 1.
The expression message[i++] increments i after it was used as an index into message, so that next time we will look at the next character in the string. So, while (message[i++] != '\n') combines steps 2 and 3.
The same in for-loop:
int i;
for (i = 0; scanf("%c", &message[i]) && message[i] != '\n'; ++i);
But as #unwind pointed, it's better not to use char-by-char input.