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
Related
A palindrome is a word that reads the same from left to right and from right to left.
I wrote a program that finds palindromes from a console.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define SIZE 100
int main() {
int i = 0, c;
int left, right;
char string[SIZE];
while (EOF != (c = getchar()) || (c = getchar()) != '\n') {
if (isspace(c) != 0) {
if (i > 0) {
left = 0;
right = i - 1;
while (right > left) {
if (string[left] != string[right]) {
i = 0;
break;
}
++left;
--right;
}
if (left >= right) {
while (i > 0)
printf("%c", string[--i]);
printf("%c", c);
}
i = 0;
}
if (c == '\n')
break;
}
else {
string[i++] = c;
}
}
}
For example, we enter the words: dad sad mum. She outputs: dad mum. But if we write dad sad or dad mum sad. The output will be: dad mum.
That is, an extra space is printed when the last word we read is not a palindrome. How can you get around this situation?
Code is convoluted
First read input properly and form a string.
for (i = 0; i < SIZE - 1; i++) [
int ch = getchar();
if (ch == EOF || ch == '\n') {
break;
}
string[i++] = (char) ch;
}
string[i] = 0;
Then process the string in string[]. Only print spaces when needed.
const char *separator = "";
int i = 0;
while (string[i]) {
// Beginning of a word?
if (!isspace(string[i])) {
int start = i;
int end = i;
while (!isspace(string[end+1]) && string[end+1]) {
end++;
}
// At this point, start indexes the 1st char of the word
// and end indexes the last char of the word
// Now find if a palindrome
while (start <= end && string[start] == string[end]) {
start++;
end--;
}
// Found a palindrome?
if (start > end) {
fputs(separator, stdout);
separator = " "; // print a space _next_ time
while (!isspace(string[i]) && string[i]) {
fputc(string[i++], stdout);
}
} else {
i = end + 1;
}
} else {
i++;
}
}
fputc('\n', stdout);
Life is easier if you just read the string all at once, then process the string.
char s[1000];
fgets( s, sizeof(s), stdin );
char * p = strchr( s, '\n' );
if (p) *p = '\0';
If you wanted to read one character at a time you should read once, test twice:
int c;
while ( ((c = getchar()) != '\n') and (c != EOF) )
But trying to compute the palindrome-ness at the same time as reading seriously makes your algorithm waaaaay more complicated than it needs to be. Read a string first, then compute.
Now you can use integer indices from each end of the string. If you can get them to meet (or cross) then you’ve got a palindrome. Hint: put that in a function:
bool is_palindrome( const char * s )
{
int left = 0;
int right = strlen(s) - 1;
...
}
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;
}
So my program should get input from an user and store it in an array. After that if the input string includes three 'a's in a row it should be replaced with a single '*'. However I can't seem to get it right. It only replaces the first a with a *. I tried to replace the following 2 a with a blank but the output looks funny.
For this exercise I have to use putchar() and getchar().
Thank you in advance.
#include <stdio.h>
char c;
char buffer[256];
int counter= 0;
int i;
int main()
{
while ((c = getchar()) != '\n') {
buffer[counter] =c;
counter++;
if (counter >255) {
break;
}
}
for(i=0; i<256; i++) {
if(buffer[i]== 'a'&&buffer[i+1]=='a'&&buffer[i+2]=='a')
{
buffer[i]= '*';
buffer[i+1]=' ';
buffer[i+2]=' ';
}
putchar(buffer[i]);
}
putchar('\n');
return 0;
}
So my program should get input from an user and store it in an array.
After that if the input string includes three 'a's in a row it should
be replaced with a single '*'. However I can't seem to get it right.
You almost got it! Just move index by 2 to and continue.
#include <stdio.h>
char c;
char buffer[256];
int counter= 0;
int i;
int main(void)
{
while ((c = getchar()) != '\n') {
buffer[counter] =c;
counter++;
if (counter >= 255) {
break;
}
}
buffer[counter] ='\0';
for(i=0; i<256; i++) {
if(buffer[i]== 'a'&&buffer[i+1]=='a'&&buffer[i+2]=='a')
{
buffer[i]= '*';
putchar(buffer[i]);
i = i + 2;
continue;
}
putchar(buffer[i]);
}
putchar('\n');
return 0;
}
Test:
123aaa456aaa78
123*456*78
In string you must assign a end of character at the end and that is call null character \0 or just a numeric 0. Correct your code like below:-
while ((c = getchar()) != '\n') {
buffer[counter] =c;
counter++;
if (counter >=255) {
break;
}
}
buffer[counter] ='\0';// or buffer[counter] =0;
To avoid side effect in a string array always set all its value with 0 first:-
char buffer[256];
memset(buffer, 0, sizeof(buffer));
If you want to change the number of characters, you will need to create a different buffer to copy the output to.
If you really just want to output to the console, you could just write every character until you hit your matching string.
#include <stdio.h>
char c;
char buffer[256];
char output[256];
int counter= 0;
int i, j;
int main()
{
while ((c = getchar()) != '\n') {
buffer[counter] = c;
counter++;
if (counter >255) {
break;
}
}
buffer[counter] = 0;
for(i=0, j=0; i<256; i++, j++) {
if(buffer[i] == 'a' && buffer[i+1] == 'a'&& buffer[i+2] == 'a')
{
output[j]= '*';
i += 2;
}
else
output[j] = buffer[i];
putchar(output[j]);
}
putchar('\n');
return 0;
}
There are multiple problems in your code:
there is no reason to make all these variables global. Declare them locally in the body of the main function.
use int for the type of c as the return value of getchar() does not fit in a char.
you do not check for EOF.
your test for buffer overflow is off by one.
you do not null terminate the string in buffer. You probably make buffer global so it is initialized to all bits 0, but a better solution is to set the null terminator explicitly after the reading loop.
to replace a sequence of 3 characters with a single one, you need to copy the rest of the string.
You can use a simple method referred as the 2 finger approach: you use 2 different index variables into the same array, one for reading, one for writing.
Here is how it works:
#include <stdio.h>
int main() {
char buffer[256];
int c;
size_t i, j, counter;
for (counter = 0; counter < sizeof(buffer) - 1; counter++) {
if ((c = getchar()) == EOF || c == '\n')
break;
buffer[counter] = c;
}
buffer[counter] = '\0';
for (i = j = 0; i < counter; i++, j++) {
if (buffer[i] == 'a' && buffer[i + 1] == 'a' && buffer[i + 2] == 'a') {
buffer[j] = '*';
i += 2;
} else {
buffer[j] = buffer[i];
}
}
buffer[j] = '\0'; /* set the null terminator, the string may be shorter */
printf("modified string: %s\n", buffer);
return 0;
}
#include <stdio.h>
#define MAXLENGTH 1000
void get_input(char ch[], int maxline);
void replace_blanks(char ch[], int z);
int main(void)
{
char ch[MAXLENGTH];
int z;
z = 0;
printf("Please enter some input. ");
get_input(ch,MAXLENGTH);
replace_blanks(ch,MAXLENGTH);
while(putchar(ch[z]) != EOF)
{
++z;
}
return 0;
}
void get_input(char ch[], int lim)
{
int z, i;
z = 0;
while((i = getchar()) != EOF && z < lim-1 && i != '\n')
{
ch[z] = i;
z++;
}
if(i == '\n')
{
ch[z] = i;
z++;
}
ch[z] = '\0';
}
void replace_blanks(char ch[], int lim)
{
char ch_copy[lim];
int i, arrayindex, copy_counter;
copy_counter = 0;
arrayindex = 0;
i = arrayindex;
while(ch[arrayindex] != EOF && arrayindex < lim-1){
if(ch[arrayindex] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
}
else if(ch[arrayindex] == ' ' && ch[i] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
} else {
i = arrayindex;
arrayindex++;
}
}
ch_copy[arrayindex] = '\0';
for(arrayindex = 0; ch_copy[arrayindex] != EOF && arrayindex < lim-1; arrayindex++){
printf("%d", arrayindex);
ch[arrayindex] = ch_copy[arrayindex];
}
ch[arrayindex] = '\0';
}
Output from this functon from the printf() is
Please enter some input. hello hi
0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998hello hi
Segmentation fault: 11
No no, declare ch as char[]:
char ch[MAXLENGTH];
While possible, it's definitely possible to store strings in an int array,
you shouldn't do that at all.
I also would write your get_input like this:
int get_input(char *ch, size_t lim)
{
if(!fgets(ch, lim, stdin))
return 0;
// removing possible \n
ch[strcspn(ch, "\n")] = 0;
return 1;
}
The logic behind the algorithm seems to be OK, however your while and for
conditions are a little bit strange and it caused problems when stepping through
the debugger.
while(ch[arrayindex] != EOF && arrayindex < lim-1)
Don't check for EOF, you shouldn't write an EOF in
a string, because EOF is an signed int and doesn't fit in a char. If you
read a line with fgets, there is never going to be a EOF in the string. Also
because you did while((i = getchar()) != EOF && z < lim-1 && i != '\n') in
the read function, you are not going to have an EOF in the string. You should
check for '\0' which is the only correct way to terminate a string.
The correct condition would be:
while(ch[arrayindex] != '\0' && arrayindex < lim-1)
If you are checking for the bounds, then it would be better to have that first
and then check for the end of string.
while(arrayindex < lim-1 && ch[arrayindex])
Here I omitted the != '\0' because '\0' == 0.
After the loop you should do
ch_copy[copy_counter] = '\0';
Use copy_counter, not arrayindex, because arrayindex is the index for the
original, where multiple blanks are stored. copy_counter is the index for the
copy.
But if prior of the while loop you did:
memset(ch_copy, 0, lim);
then the whole buffer would be initalized with 0 and you won't need to worry
about the 0 terminating because the copy will never be larger than the original.
Lastly, the condition in the for loop should be corrected with the same logic
as for the while loop. Here you don't need to check for the boundaries,
because you know that the copy is never be larger than the original:
for(arrayindex = 0; ch_copy[arrayindex]; arrayindex++){
ch[arrayindex] = ch_copy[arrayindex];
}
ch[arrayindex] = 0;
Or you could just use strcpy:
strcpy(ch, ch_copy);
So the function should look like this:
void replace_blanks(char ch[], int lim)
{
char ch_copy[lim];
int i, arrayindex, copy_counter;
memset(ch_copy, 0, lim);
copy_counter = 0;
arrayindex = 0;
i = arrayindex;
while(arrayindex < lim -1 && ch[arrayindex]){
if(ch[arrayindex] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
}
else if(ch[arrayindex] == ' ' && ch[i] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
} else {
i = arrayindex;
arrayindex++;
}
}
strcpy(ch, ch_copy);
}
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;
}