I was solving one of the exercises from K&R but I'm having a minor problem.
The exercise is to print a histogram of the length of words in its input.
Here's my code:
#include <stdio.h>
#define IN 1
#define OUT 0
int main(){
//Histogram of the length of words
int c, state, len, i;
state = OUT;
printf("Histogram\n");
while ((c = getchar()) != EOF){
if (c != ' ' && c != '\n' && c != '\t' && c != '\r'){
state = IN;
len++;
} else if (state == IN){
for (i = 0; i < len; i++){
putchar('[');
putchar(']');
}
len = 0;
putchar('\n');
state = OUT;
}
}
return 0;
}
The text file I used was:
Hello World! This is a text
The output of the program was:
Histogram
[][][][][]
[][][][][][]
[][][][]
[][]
[]
As it can be seen, the program terminated before printing out the histogram for the last word 'text'.
Is this because the text editor on Windows does not automatically put '\r\n' at the end? If so, how can I fix this problem?
Thank you.
Your loop end when getchar() return EOF so you never go in the else if at the end.
Example:
#include <stdio.h>
#include <stdbool.h>
int main(void) {
printf("Histogram\n");
size_t len = 0;
bool running = true;
while (running) {
switch (getchar()) {
case EOF:
running = false;
case ' ':
case '\n':
case '\t':
case '\r':
if (len != 0) {
printf("\n");
len = 0;
}
break;
default:
printf("[]");
len++;
}
}
}
Move the tests around:
while (true)
{
const int c = getchar();
if (c != ' ' && c != '\n' && c != '\t' && c != '\r' && c != EOF)
{
state = IN;
len++;
}
else if (state == IN)
{
// ...
}
if (c == EOF) break;
}
Related
I have experienced some problem with segmentation when I'm learning through C, my aim is to swap the tabs in the program with spaces:
I have used the get_line template and modified the code to suit the situation. Here is the whole coded solution:
#include <stdio.h>
#define MAXLINE 1000
char line[MAXLINE];
char detabline[MAXLINE];
int get_line(void);
int main(void){
int len;
int i;
int nt = 0;
extern char detabline[];
extern char line[];
while ((len = get_line()) > 0){
for (i = 0; i < len; ++i){
if (line[i] == '\t'){
printf("%s", " ");
}
else{
printf("%s", line[i]);
}
}
}
return 0;
}
int get_line(void){
int c, i, nt;
nt = 0;
extern char line[];
for (i = 0; i < (MAXLINE - 1) && (c = getchar()) != EOF && ((c != '\t') || (c != '\n')); ++i){
line[i] = c;
}
if (c == '\n'){
line[i] = c;
++i;
}
else if (c == '\t'){
++nt;
}
line[i] = '\0';
return i;
}
The problem is to locate which memory isn't allocated correctly. I may have some redundant code in the solution by the way.
regarding:
for (i = 0; i < (MAXLINE - 1) && (c = getchar()) != EOF && ((c != '\t') || (c != '\n')); ++i){
this expression:
(c != '\t')
will result in no tab character ever being in the line[] array.
this expression:
(c != '\n')
will result in no newline character sequence ever being in the line[] array.
then, due those expressions, the line[] array will not be updated (ever again) when a tab or a newline is encountered due to those expressions causing an early exit from the for() loop
The following proposed code:
cleanly compiles
performs the desired functionality
and now, the proposed code:
#include <stdio.h>
#define MAXLINE 1000
char line[MAXLINE];
int main(void)
{
int i = 0;
int ch;
while ( i< MAXLINE-1 && (ch = getchar()) != EOF && ch != '\n' )
{
if ( ch == '\t')
{
line[i] = ' ';
}
else
{
line[i] = (char)ch;
}
i++;
}
printf( "%s\n", line );
}
Post a comment if you want further details about the proposed code.
I am reading in a string character by character then for each word found(separated by space) counting the length of each word, and finally printing all that information to the screen.
Sample run: trickier to master
n=8, s=[trickier]
n=2, s=[to]
n=6, s=[master]
n=0, s=[]
n=-1, s=[]
This is correct what I get is this:
n=0, s=[]
n=0, s=[]
n=8, s=[trickier]
n=2, s=[to]
n=0, s=[]
n=6, s=[master]
n=0, s=[]
n=-1, s=[]
The problem is the leading spaces in the string I have looked at a lot of examples of how to trim the leading spaces, but I couldn't get anything to work with my current source code.
Code:
#include "getword.h"
int getword(char *w) {
int iochar;
int index = 0;
int numberofchars = 0;
if (numberofchars == 0 && iochar == '\n') {
w[index] = '\0';
iochar = EOF;
return 0;
}
if (iochar == EOF && numberofchars == 0) {
w[index] = '\0';
return -1;
}
while ((iochar = getchar()) != EOF) {
if (iochar != ' ' && iochar != '\n') {
w[index] = iochar;
index++;
numberofchars++;
} else {
w[index] = '\0';
if (strcmp(w, "done") == 0) {
return -1;
} else {
return numberofchars;
}
}
} //after while loop
} // end of function
int main() {
int c;
char s[STORAGE];
for (;;) {
(void)printf("n=%d, s=[%s]\n", c = getword(s), s);
if (c == -1)
break;
}
}
The code is way too complicated, with some useless and bogus tests producing undefined behavior:
testing iochar in getword() before you even read it with getchar() makes no sense.
combining reading, testing and writing the words in a single printf() call is bogus too: you should instead read, then test, then output if not done.
Here is a simplified version:
#include <stdio.h>
#include <string.h>
#define STORAGE 50
// read a word into an array of size `size`.
// return the number of characters read.
int getword(char *w, size_t size) {
int c;
size_t i = 0;
while (i + 1 < size && (c = getchar()) != EOF) {
if (c == ' ' || c == '\t' || c == '\n') {
if (i == 0)
continue; // ignore leading spaces
else
break; // stop on white space following the word.
}
w[i++] = c;
}
w[i] = '\0';
return i;
}
int main() {
char s[STORAGE];
int len;
while ((len = getword(s, sizeof s)) != 0) {
if (!strcmp(s, "done"))
break;
printf("n=%d, s=[%s]\n", len, s);
}
return 0;
}
I tried to make the code produce desired output, but this is all I could do. There were some bugs which I thought and so I fixed them. See the comments in the code for more details. Hope that solves the problem.
int getword(char * w) {
int iochar = 0;
int index = 0;
int numberofchars = 0;
// I really don't know why those if conditions were required
// Thought they were useless so removed them
while ((iochar = getchar()) != EOF) {
if (iochar != ' ' && iochar != '\n') {
w[index++] = iochar; // slight change here
numberofchars++;
} else {
w[index] = '\0';
// I don't know what this condition is supposed to mean
// so I ignored it
if (strcmp(w, "done") == 0) {
return -1;
} else {
return numberofchars;
}
}
} //after while loop
// Since EOF is encountered, no more characters to read
// So terminate the string with '\0'
w[index] = '\0';
// Here after the loop you should check if some characters were read, but not
// handled. If there are any, return them because that's what you last read
// before EOF was encountered
return (numberofchars > 0 ? numberofchars : -1);
} // end of function
int main()
{
int c;
char s[STORAGE];
for (;;) {
// Put the if condition before printing because if -1 is returned
// it doesn't make sense to print the string at all
c = getword(s);
if (c == -1) break;
printf("n=%d, s=[%s]\n", c, s);
}
}
Here's where I tested this: http://ideone.com/bmfaA3
I wrote this program that replaces two spaces with an '*'.
How do I modify the code so that it does the same thing regardless of the string size? Is it even possible only using putchar and getchar?
#include <stdio.h>
int c;
char buffer[256];
int counter= 0;
int i;
int main()
{
while ((c = getchar()) != '\n'&&c!=EOF) {
buffer[counter] =c;
counter++;
if (counter >=255) {
break;
}
}
for(i=0; i<256; i++) {
if(buffer[i]== ' '&&buffer[i+1]==' ')
{
buffer[i]= '*';
putchar(buffer[i]);
i = i + 2;
continue;
}
putchar(buffer[i]);
}
putchar('\n');
return 0;
}
The problem statement doesn't require you to store the complete input in a buffer. The decision on what character to output only depends on the last two characters of input. Consider the following code:
#include <stdio.h>
int main(void)
{
// two variables for the last two input characters
int c = EOF, last = EOF;
while ((c = getchar()) != EOF)
{
// if both are a space, store a single '*' instead
if (c == ' ' && last == ' ')
{
c = '*';
last = EOF;
}
// print the output, and shift the buffer
if (last != EOF)
putchar(last);
last = c;
}
// take care of the last character in the buffer after we see EOF
if (last != EOF)
putchar(last);
}
no need for malloc and friends at all. This is a good expample for a problem that requires you to think carefully, before writing code, in order to not waste unnecessary resources on buffers.
Code for just printing:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char prev = EOF, curr;
while ((curr =(char)getchar()) != '\n' && curr != EOF)
{
if(curr==' '&&prev==' ')
{
curr = '*';
prev = EOF;
}
if (prev != EOF)
putchar(prev);
prev = curr;
}
putchar(prev);
return 0;
}
Using realloc for actually changing the string:
#include <stdio.h>
#include <stdlib.h>
int main() {
unsigned int len_max = 128;
char *m = malloc(len_max);
char c;
int counter= 0;
int i;
int current_size = 256;
printf("please input a string\n");
while ((c = getchar()) != '\n' && c != EOF)
{
m[counter] =(char)c;
counter++;
if(counter == current_size)
{
current_size = i+len_max;
m = realloc(m, current_size);
}
}
for(i=0; i<counter; i++)
{
if(m[i]== ' '&&m[i+1]==' ')
{
m[i]= '*';
putchar(m[i]);
i = i + 2;
continue;
}
putchar(m[i]);
}
putchar('\n');
free(m);
m = NULL;
return 0;
}
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned long c;
unsigned long line;
unsigned long word;
char ch;
c = 0;
line = 0;
word = 0;
while((ch = getchar()) != EOF)
{
c ++;
if (ch == '\n')
{
line ++;
}
if (ch == ' ' || ch == '\n' || ch =='\'')
{
word ++;
}
}
printf( "%lu %lu %lu\n", c, word, line );
return 0;
}
My program works fine for the most part, but when I add extra spaces, it counts the spaces as extra words. So for example, How are you? is counted as 10 words, but I want it to count as 3 words instead. How could I modify my code to get it to work?
I found a way to count words and between them several spaces the program will count only the words and not the several spaces also as words
here is the code:
nbword is the number of words, c is the character typed and prvc is the previously typed character.
#include <stdio.h>
int main()
{
int nbword = 1;
char c, prvc = 0;
while((c = getchar()) != EOF)
{
if(c == ' ')
{
nbword++;
}
if(c == prvc && prvc == ' ')
nbword-;
if(c == '\n')
{
printf("%d\n", nbword);
nbword = 1:
}
prvc = c;
}
return 0:
}
This is one possible solution:
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned long c;
unsigned long line;
unsigned long word;
char ch;
char lastch = -1;
c = 0;
line = 0;
word = 0;
while((ch = getchar()) != EOF)
{
c ++;
if (ch == '\n')
{
line ++;
}
if (ch == ' ' || ch == '\n' || ch =='\'')
{
if (!(lastch == ' ' && ch == ' '))
{
word ++;
}
}
lastch = ch;
}
printf( "%lu %lu %lu\n", c, word, line );
return 0;
}
Hope this helped, good luck!
i was wondering if i could get some help for my code. I put some partial code below
/*reads char by char til EOF*/
while((c = getchar()) != EOF)
{
if(c == '\t')
{
putchar(' ');
}
else if(c == ' ')
{
putchar('d');
}
else
{
putchar(c);
}
}
What I am trying to do right now is squeeze space characters entered by the user. So if the user puts in:
a[SPACE][SPACE][SPACE][SPACE][SPACE][SPACE][SPACE][SPACE]a
The output should be just
a[SPACE]a
Right now i have it set up that it replaces all spaces for d's for testing purposes. How would I change my code so that it just prints out 1 space instead of all the spaces the user puts in.
Thanks for any help in advance.
Just keep a whitespace flag:
int lastWasSpace = 0;
while((c = getchar()) != EOF) {
if(c == '\t' || c == ' ') { // you could also use isspace()
if(!lastWasSpace) {
lastWasSpace = 1;
putchar(c);
}
} else {
lastWasSpace = 0;
}
}
One solution:
/*reads char by char til EOF*/
int hasspace = 0;
while((c = getchar()) != EOF)
{
if (isspace(c))
hasspace = 1;
}
else
{
if (hasspace)
{
hasspace = 0;
putchar(' ');
}
putchar(c);
}
}
First things first, how have you declared c?:
while((c = getchar()) != EOF)
If c is a char, then it cannot hold all characters and an EOF. Be sure c is declared with a datatype larger than char (int is usual).
Next, you can handle compressing multiple spaces with a cheap trick:
int space_seen = 0;
while((c = getchar()) != EOF)
{
if(c == '\t')
{
putchar(' ');
}
else if(c == ' ')
{
if (!space_seen)
{
putchar('d');
space_seen = 1;
}
}
else
{
putchar(c);
space_seen = 0;
}
}
This trick is also good for keeping track of parsing strings, too.
jcomeau#intrepid:/tmp$ cat compress.c; echo 'this is a test' | ./compress
#include <stdio.h>
int main() {
int c, lastchar = 'x';
while ((c = getchar()) != EOF) {
if (c == '\t' || c == ' ') {
if (lastchar != ' ') {
putchar(' ');
lastchar = ' ';
}
} else {
putchar(c);
lastchar = c;
}
}
}
this is a test
Record when you printed a space, and don't print them anymore until you find another letter.
Using your code as a base:
unsigned char space = 0;
/* reads char by char until EOF */
while((c = getchar()) != EOF)
{
if(c == '\t')
{
putchar(' ');
}
else if(c == ' ')
{
/* state specific action */
if(space == 0) {
putchar('d');
space = 1; /* state transition */
}
}
else
{
/* state transition */
if(space == 1) {
space = 0;
}
putchar(c);
}
}
There you go. A very, very simple state machine. It's easy as that!