Write a program to "fold" long input lines into two or more shorter lines after the last non-blank character that occurs before the n-th column of input. Make sure your program does something intelligent with very long lines, and if there are no blanks or tabs before the specified column.
The algorithm I decided to follow for this was as follows:
If length of input line < maxcol (the column after which one would have to fold), then print the line as it is.
If not, from maxcol, I check towards it's left, and it's right to find the closest non-space character, and save them as 'first' and 'last'. I then print the character array from line[0] to line[first] and then the rest of the array, from line[last] to line[len] becomes the new line array.
Here's my code:
#include <stdio.h>
#define MAXCOL 5
int getline1(char line[]);
int main()
{
char line[1000];
int len, i, j, first, last;
len = getline1(line);
while (len > 0) {
if (len < MAXCOL) {
printf("%s\n", line);
break;
}
else {
for (i = MAXCOL - 1; i >= 0; i--) {
if (line[i] != ' ') {
first = i;
break;
}
}
for (j = MAXCOL - 1; j <= len; j++) {
if (line[j] != ' ') {
last = j;
break;
}
}
//printf("first %d last %d\n", first, last);
for (i = 0; i <= first; i++)
putchar(line[i]);
putchar('\n');
for (i = 0; i < len - last; i++) {
line[i] = line[last + i];
}
len -= last;
first = last = 0;
}
}
return 0;
}
int getline1(char line[])
{
int c, i = 0;
while ((c = getchar()) != EOF && c != '\n')
line[i++] = c;
if (c == '\n')
line[i++] = '\n';
line[i] = '\0';
return i;
}
Here are the problems:
It does not do something intelligent with very long lines (this is fine, as I can add it as an edge case).
It does not do anything for tabs.
I cannot understand a part of the output.
For example, with the input:
asd de def deffff
I get the output:
asd
de
def
defff //Expected until here
//Unexpected lines below
ff
fff
deffff
deffff
deffff
Question 1 - Why do the unexpected lines print? How do I make my program/algorithm better?
Eventually, after spending quite some time with this question, I gave up and decided to check the clc-wiki for solutions. Every program here did NOT work, save one (The others didn't work because they did not cover certain edge cases). The one that worked was the largest one, and it did not make any sense to me. It did not have any comments, and neither could I properly understand the variable names, and what they represented. But it was the ONLY program in the wiki that worked.
#include <stdio.h>
#define YES 1
#define NO 0
int main(void)
{
int TCOL = 8, ch, co[3], i, COL = 19, tabs[COL - 1];
char bls[COL - 1], bonly = YES;
co[0] = co[1] = co[2] = 0;
while ((ch = getchar()) != EOF)
{
if (ch != '\t') {
++co[0];
++co[2];
}
else {
co[0] = co[0] + (TCOL * (1 + (co[2] / TCOL)) - co[2]);
i = co[2];
co[2] = TCOL + (co[2] / TCOL) * TCOL;
}
if (ch != '\n' && ch != ' ' && ch != '\t')
{
if (co[0] >= COL) {
putchar('\n');
co[0] = 1;
co[1] = 0;
}
else
for (i = co[1]; co[1] > 0; --co[1])
{
if (bls[i - co[1]] == ' ')
putchar(bls[i - co[1]]);
else
for (; tabs[i - co[1]] != 0;)
if (tabs[i - co[1]] > 0) {
putchar(' ');
--tabs[i - co[1]];
}
else {
tabs[i - co[1]] = 0;
putchar(bls[i - co[1]]);
}
}
putchar(ch);
if (bonly == YES)
bonly = NO;
}
else if (ch != '\n')
{
if (co[0] >= COL)
{
if (bonly == NO) {
putchar('\n');
bonly = YES;
}
co[0] = co[1] = 0;
}
else if (bonly == NO) {
bls[co[1]] = ch;
if (ch == '\t') {
if (TCOL * (1 + ((co[0] - (co[2] - i)) / TCOL)) -
(co[0] - (co[2] - i)) == co[2] - i)
tabs[co[1]] = -1;
else
tabs[co[1]] = co[2] - i;
}
++co[1];
}
else
co[0] = co[1] = 0;
}
else {
putchar(ch);
if (bonly == NO)
bonly = YES;
co[0] = co[1] = co[2] = 0;
}
}
return 0;
}
Question 2 - Can you help me make sense of this code and how it works?
It fixes all the problems with my solution, and also works by reading character to character, and therefore seems more efficient.
Question 1 - Why do the unexpected lines print? How do I make my program/algorithm better?
You are getting the unexpected lines in the output because after printing the array, you are not terminating the new line array with null character \0 -
Here you are copying character from starting from last till len - last, creating a new line array:
for (i = 0; i < len - last; i++) {
line[i] = line[last + i];
}
You have copied the characters but the null terminating character is still at its original position. Assume the input string is:
asd de def deffff
So, initially the content of line array will be:
"asd de def deffff\n"
^
|
null character is here
Now after printing asd, you are copying characters from last index of line till len - last index to line array itself starting from 0 index. So, after copying the content of line array will be:
"de def deffff\n deffff\n"
|____ _____|
\/
This is causing the unexpected output
(null character is still at the previous location)
So, after for loop you should add the null character just after the last character copied, like this:
line [len - last] = '\0';
With this the content of line array that will be processed in the next iteration of while loop will be:
"de def deffff\n"
One more thing, in the line array you can see the \n (newline) character at the end. May you want to remove it before processing the input, you can do:
line[strcspn(line, "\n")] = 0;
Improvements that you can do in your program:
1. One very obvious improvement that you can do is to use pointer to the input string while processing it. With the help of pointer you don't need to copy the rest of the array, apart from processed part, again to the same array till the program process the whole input. Initialize the pointer to the start of the input string and in every iteration just move the pointer to appropriate location and start processing from that location where pointer is pointing to.
2. Since you are taking the whole input first in a buffer and then processing it. You may consider fgets() for taking input. It will give better control over the input from user.
3. Add a check for line array overflow, in case of very long input. With fgets() you can specify the maximum number of character to be copied to line array from input stream.
Question 2 - Can you help me make sense of this code and how it works?
The program is very simple, try to understand it at least once by yourself. Either use a debugger or take a pen and paper, dry run it once for small size input and check the output. Increase the input size and add some variations like multiple space characters and check the program code path and output. This way you can understand it very easily.
Here's another (and I think better) solution to this exercise :
#include <stdio.h>
#define MAXCOL 10
void my_flush(char buf[]);
int main()
{
int c, prev_char, i, j, ctr, spaceleft, first_non_space_buf;
char buf[MAXCOL+2];
prev_char = -1;
i = first_non_space_buf = ctr = 0;
spaceleft = MAXCOL;
printf("Just keep typing once the output has been printed");
while ((c = getchar()) != EOF) {
if (buf[0] == '\n') {
i = 0;
my_flush(buf);
}
//printf("Prev char = %c and Current char = %c and i = %d and fnsb = %d and spaceleft = %d and j = %d and buf = %s \n", prev_char, c, i, first_non_space_buf, spaceleft, j, buf);
if ((((prev_char != ' ') && (prev_char != '\t') && (prev_char != '\n')) &&
((c == ' ') || (c == '\t') || (c == '\n'))) ||
(i == MAXCOL)) {
if (i <= spaceleft) {
printf("%s", buf);
spaceleft -= i;
}
else {
putchar('\n');
spaceleft = MAXCOL;
for (j = first_non_space_buf; buf[j] != '\0'; ++j) {
putchar(buf[j]);
++ctr;
}
spaceleft -= ctr;
}
i = 0;
my_flush(buf);
buf[i++] = c;
first_non_space_buf = j = ctr = 0;
}
else {
if (((prev_char == ' ') || (prev_char == '\t') || (prev_char == '\n')) &&
((c != ' ') && (c != '\t') && (c != '\n'))) {
first_non_space_buf = i;
}
buf[i++] = c;
buf[i] = '\0';
}
prev_char = c;
}
printf("%s", buf);
return 0;
}
void my_flush(char buf[])
{
int i;
for (i = 0; i < MAXCOL; ++i)
buf[i] = '\0';
}
Below is my solution, I know the thread is no longer active but my code might help someone who's facing issues to grasp the already presented code snippets.
*EDIT
explaination
Keep reading input unless the input contains '\n', '\t' or there've been
atleast MAXCOl chars.
Incase of '\t', use expandTab to replace with required spaces and use printLine if it doesn't exceed MAXCOl.
Incase of '\n', directly use printLine and reset the index.
If index is 10:
find the last blank using findBlank ad get a new index.
use printLine to print the current line.
get new index as 0 or index of newly copied char array using the newIndex function.
code
/* fold long lines after last non-blank char */
#include <stdio.h>
#define MAXCOL 10 /* maximum column of input */
#define TABSIZE 8 /* tab size */
char line[MAXCOL]; /* input line */
int expandTab(int index);
int findBlank(int index);
int newIndex(int index);
void printLine(int index);
void main() {
int c, index;
index = 0;
while((c = getchar()) != EOF) {
line[index] = c; /* store current char */
if (c == '\t')
index = expandTab(index);
else if (c == '\n') {
printLine(index); /* print current input line */
index = 0;
} else if (++index == MAXCOL) {
index = findBlank(index);
printLine(index);
index = newIndex(index);
}
}
}
/* expand tab into blanks */
int expandTab(int index) {
line[index] = ' '; /* tab is atleast one blank */
for (++index; index < MAXCOL && index % TABSIZE != 0; ++index)
line[index] = ' ';
if (index > MAXCOL)
return index;
else {
printLine(index);
return 0;
}
}
/* find last blank position */
int findBlank(int index) {
while( index > 0 && line[index] != ' ')
--index;
if (index == 0)
return MAXCOL;
else
return index - 1;
}
/* re-arrange line with new position */
int newIndex(int index) {
int i, j;
if (index <= 0 || index >= MAXCOL)
return 0;
else {
i = 0;
for (j = index; j < MAXCOL; ++j) {
line[i] = line[j];
++i;
}
return i;
}
}
/* print line until passed index */
void printLine(int index) {
int i;
for(i = 0; i < index; ++i)
putchar(line[i]);
if (index > 0)
putchar('\n');
}
I'm fairly new to coding and am currently enrolled in a course at school teaching C. We have been given an assignment that requires as follows:
Write a program that inputs three lines of text and uses the function strchr to determine the number of occurrences of each letter of the alphabet (uppercase and lowercase should be counted as the same). Store the totals for each letter in an array and print the result.
Here's the code I've written so far:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define SIZE 100
int main(void) {
int alphabet[26] = { 0 };
char string[3][SIZE];
int i, j;
int c;
printf("Enter three lines of text:\n");
for (i = 0; i <= 2; i++) {
fgets(string[i], SIZE, stdin);
}
for (i = 0; i <= 2; i++) {
for (j = 0; &string[i][j] != '\0'; j++) {
string[i][j] = tolower(string[i][j]);
}
for (j = 0; &string[i][j] != '\0'; j++) {
if (strchr(&string[i][j], ('a' + j)) != NULL) {
alphabet[j]++;
}
}
}
printf("\n");
for (i = 0; i < 26; i++) {
printf("%c: %d\n", ('a' + i), alphabet[i]);
}
printf("\n");
return 0;
}
The problem with the current program I have is that the counter for the array alphabet[] doesn't seem to be incrementing the count properly.
The output should count, for example, increment by 1 for each occurrence of every letter, but the results are all 0.
Any other tips or words of advice are greatly appreciated!
Your test for end of line is wrong,
no need to loop several time just parse the string and count the letters
You want letter between 'a'and 'z', check if the char is in the range and count it
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define SIZE 100
int main(void) {
int alphabet[26] = { 0 };
char string[3][SIZE];
int i, j;
printf("Enter three lines of text:\n");
for (i = 0; i <= 2; i++) {
fgets(string[i], SIZE, stdin);
}
for (i = 0; i <= 2; i++) {
for (j = 0; string[i][j] != '\0'; j++) {
char c = tolower(string[i][j]);
if (c >= 'a' && c <= 'z') {
alphabet[c - 'a']++;
}
}
}
printf("\n");
for (i = 0; i < 26; i++) {
printf("%c: %d\n", ('a' + i), alphabet[i]);
}
printf("\n");
return 0;
}
You need to change loop terminating condition from &string[i][j] != '\0'; to string[i][j] != '\0';
strchr will return the address from the string where match was found, so you should save the non null address to pass it to next call to strchr
Something like this:
tmpPtr = &string[i][j];
while ((tmpPtr=strchr(tmpPtr, string[i][j])) != NULL) {
alphabet[string[i][j] - 'a']++;
}
This is a question from K&R:-
Write a program to print a histogram of the lengths of words in its input.It is easy to draw the histogram with bars horizontal; but a vertical orientation is more challenging.
I am not supposed to use any library functions because this is only a tutorial introduction!
I have written the following program to do so but it have some bugs:-
1)If there is more than one white-space character between words, the program doesn't work as expected.
2)How do I know the maximum value of 'k' I mean how to know how many words are there in the input?
Here is the code:-
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
#define MAX_WORDS 100
int main(void)
{
int c, i=0, k=1, ch[MAX_WORDS] = {0};
printf("enter the words:-\n");
do
{
while((c=getchar())!=EOF)
{
if(c=='\n' || c==' ' || c=='\t')
break;
else
ch[i]++;
}
i++;
}
while(i<MAX_WORDS);
do
{
printf("%3d|",k);
for(int j=1;j<=ch[k];j++)
printf("%c",'*');
printf("\n");
k++;
}
while(k<10);
}
This program will work fine even if there are more than one newline characters in between the two words and numWords will give you the numbers of words.
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
int ch, cha[100] = {0}, k = 1;
int numWords = 0;
int numLetters = 0;
bool prevWasANewline = true; //Newlines at beginning are ignored
printf("Enter the words:-\n");
while ((ch = getchar()) != EOF && ch != '\n')
{
if (ch == ' ' || ch == '\t')
prevWasANewline = true; //Newlines at the end are ignored
else
{
if (prevWasANewline) //Extra nelines between two words ignored
{
numWords++;
numLetters = 0;
}
prevWasANewline = false;
cha[numWords] = ++numLetters;
}
}
do
{
printf("%3d|",k);
for(int j=0;j<cha[k];j++)
printf("%c",'*');
printf("\n");
k++;
} while(k <= numWords);
return 0;
}
Its kind of an old thread, but i had the same problem. The code above works like charm, but its kind of an overkill for the knowledge we have with K&R in the first 20 pages.
I had no idea what they meant by histogram printing and that code helped me with that.
Anyway i wrote a code myself with the knowledge i gained through the book, i hope it will be helpful to someone.
Forgive me if its a bit messy, i am just a beginner myself :D
#include <stdio.h>
#define YES 1
#define NO 0
int main(void)
{
int wnumb [100];
int i, inword, c, n, k;
n = (-1);
for (i = 0; i <=100; ++i) {
wnumb [i] = 0;
}
inword = NO;
while ((c = getchar()) != EOF) {
if ( c == ' ' || c == '\n' || c == '\t' ) {
inword = NO;
}
else if (inword == NO) {
++n;
++wnumb [n];
inword = YES;
}
else {
++wnumb [n];
}
}
for (i = 0; i <= 100; ++i) {
if (wnumb [i] > 0) {
printf ("\n%3d. | ", (i+1));
for (k = 1; k <= wnumb[i]; ++k) {
printf("*");
}
}
}
printf("\n");
}
Here is example of simple Histogram(Vertically)
#include <stdio.h>
int main()
{
int c, i, j, max;
int ndigit[10];
for (i = 0; i < 10; i++)
ndigit[i] = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
max = ndigit[0];
for (i = 1; i < 10; ++i) /* for Y-axis */
if (max < ndigit[i])
max = ndigit[i];
printf("--------------------------------------------------\n");
for (i = max; i > 0; --i) {
printf("%.3d|", i);
for (j = 0; j < 10; ++j)
(ndigit[j] >= i) ? printf(" X ") : printf(" ");
printf("\n");
}
printf(" ");
for (i = 0; i < 10; ++i) /* for X-axis */
printf("%3d", i);
printf("\n--------------------------------------------------\n");
return 0;
}
This is a K&R exercise (1-13)...
"Write a program to print a histogram
of the length of words in its input.
It is easy to draw the histogram with
bars horizontal; a vertical
orientation is more challenging."
The section was about arrays, and to be honest, I'm not sure I fully understood it. Everything up to this point was fairly easy to grasp, this was not.
Anyway I'm trying to do a histogram with horizontal bars first. Once I got that down I'll try vertical, but right now I'm not even sure where to begin with the easy version. (I slept on it, woke up, and still couldn't get it.)
I drew an example of what the program would output:
----------------------------------------------------------------
001|XX
002|XXXX
003|X
004|XXXXXXXXXX
005|XXXXXXXXXXXXXXXXXXXXXXXXX
006|XXXX
007|X
008|
009|XXXXXXXXX
010|XXX
>10|XXXX
----------------------------------------------------------------
And tried to break it (the program) down in sections. This is what I came up with:
PRINT TOP BORDER
PRINT CATEGORY, PRINT X EACH TIME CONDITION IS TRUE, PRINT NEWLINE,
REPEAT.
PRINT BOTTOM BORDER
But the more I think about it the less I think that's how it would work (because getchar() goes through one character at a time, and it wouldn't be able to go back up to put a X in the right category.) Or...
... I'm just really confused as to how I would solve this problem. Here's as far as I've been able to get code wise:
#include <stdio.h>
#define MAXWORDLENGTH 10
// print a histogram of the length of words in input. horizontal bar version
int main(void)
{
int c;
while ((c = getchar()) != EOF) {
}
return 0;
}
Could someone help enlighten me? Not necessarily with the code, maybe just pseudo code, or with some "words from the wise" as to what I need to do, or think, or something. This has just been a really big stone in the road and I'd like to get past it :/.
(I'll check back in 30 minutes)
I loved the pseudo-code! Some good thinking there, but you're still not ordering your program right.
As you said yourself, you can't read the text, go back and print an X in a particular row. If we establish that it can't be done, then there's no choice but to know all the values of the histogram beforehand.
So you should think your program as having two parts (and you'll make this kind of division in practically every program you write): first, a part that will make calculations; and then a part that will output them in a certain format (the histogram).
This tip should get you started! If you need further help, comment below.
I suggest you simplify the problem by solving it for the case of one word per line, so you can use fgets. Here's how to "eat up" lines that are too long.
Then, as often, the central data structure is the key to solving the problem. The data structure you need is an array used as frequency table:
int freq[11];
In freq[1], store the number of words/lines of length 1, in freq[2] those of length 2, etc., and in freq[0] those of length >10. You don't need to store the words since the rest of the program only needs their length. Writing out the histogram should be easy now.
I hope this isn't too much of a spoiler.
The code below prints a horizontal histogram using only the basic toolkit provided by the book so far:
#include<stdio.h>
/* Prints a horizontal histogram of the lengths of words */
#define MAX_WORDS 100
#define IN 1
#define OUT 0
main()
{
int c, length, wordn, i, j, state, lengths[MAX_WORDS];
wordn = length = 0;
state = OUT;
for (i = 0; i < MAX_WORDS; ++i) lengths[i] = 0;
while ((c = getchar()) != EOF && wordn < MAX_WORDS)
{
if (c == ' ' || c == '\t' || c == '\n')
state = OUT;
else if (wordn == 0)
{
state = IN;
++wordn;
++length;
}
else if (state == IN)
++length;
else if (state == OUT)
{
lengths[wordn] = length;
++wordn;
length = 1;
state = IN;
}
}
lengths[wordn] = length;
for (i = 1; i <= wordn; ++i)
{
printf("%3d: ",i);
for (j = 0; j < lengths[i]; j++)
putchar('-');
putchar('\n');
}
}
#include<stdio.h>
#define RESET 0
#define ON 1
main()
{
int i,wnum=0,c,wc[50];
int count=0,state;
state=RESET;
for(i=0;i<50;++i)
wc[i]=0;
/*Populating the array with character counts of the typed words*/
while((c=getchar())!=EOF)
{
if(c=='\n'||c=='\t'||c==' '||c=='"')
{
if(state!=RESET)
state=RESET;
}
else if((c>=65&&c<=90)||(c>=97&&c<=122))
{
if(state==RESET)
{
count=RESET;
++wnum;
state=ON;
}
++count;
wc[wnum-1]=count;
}
}
c=RESET;
/*Finding the character count of the longest word*/
for(i=0;i<wnum;++i)
{
if(c<wc[i])
c=wc[i];
}
/*Printing the Histogram Finally*/
for(i=c;i>0;--i)
{
for(count=0;count<wnum;++count)
{
if(wc[count]-i<0)
printf(" ");
else printf("x ");
}
printf("\n");
}
}
VERTICAL ORIENTATION: Using only the tools we learned so far in the book. And you can change the array size, wc[50]. I kept the code valid for 50 words.
Horizontal orientation should be quite simpler. I didn't try it though.
To histogram the word lengths, you are going to need to know the word lengths.
How do you define a word?
How can you measure the length of a word? Can you do it one character at a time as you read the stream, or should you buffer the input an use strtok or something similar?
You will need to accumulate data on how many occurrences of each length occur.
How will you store this data?
You will need to output the results in a pleasing form. This is fiddly but not hard.
I will link the answer below but since you asked for details the key seems to be this
Use an ARRAY of lengths i.e have an array with each element initialised to zero assume MAX wordlength to be about 30...
*have a flag while in the word and increment a counter every time a whitespace is NOT encountered
*once out of the word flag is set to "out" and the corresponding word length index item in the array is incremented i.e if word length counter is w_ctr use
array[w_ctr]++
*use the array as a table of reference for each line in a loop to print each line in the histogram so you can use the array and will now be able to determine weather the 'X' in the histogram is to be inserted or not
EDIT: sorry i didn't read the question right but the idea is simpler for Vertical histograms and the same thing can be used.
after the last step just print the horizontal histogram until counter exceeds current wordlength being printed
for(ctr=0;ctr<array[current_wordlength];ctr++)
printf('X');
End
the original is here http://users.powernet.co.uk/eton/kandr2/krx113.html
CLC-wiki is also a place see the comments for details.
//This is for horizontal histogram.
//It works for any number of lines of words where total words <= MAX
#include <stdio.h>
#define MAX 100 //Change MAX to any value.But dont give words more than MAX.
void main()
{
int w, nwords[MAX] = {0}, i = 0; //nwords is an array for storing length of each word.Length of all words initialized to 0.
while ((w = getchar()) != EOF)
{
if (w == ' ' || w == '\t' || w == '\n')
++i; //if space or tab or newline is encountered, then index of array is advanced indicating new word
else
++nwords[i]; //increment the count of number of characters in each word
} //After this step,we will have array with each word length.
for (i = 0; i < MAX; i++) //iterating through array
{
printf("\n");
for (; nwords[i] > 0; nwords[i]--)
printf("$"); //if length of word > 0 , print $ and decrement the length.This is in loop.
if (nwords[i+1] == 0) //as MAX is 100, to avoid printing blank new lines in histogram,we check the length of next word.
break; //If it is 0, then break the loop
printf("\n"); //After each word bar in histogram, new line.
}
printf("\n");
} //main
I've been also studying K&R book. An good approach is to use a int array for storing word frequencies. The array index is the word length, and the array values are the frequencies.
For example:
int histogram[15]; // declares an int array of size 15
// it is very important to initialize the array
for (int i = 0; i <= 15; ++i) {
histogram[i] = 0;
}
histogram[4] = 7; // this means that you found 7 words of length 4
Given that now you have a data structure for storing your word length frequencies, you can use the same reasoning of Word Counting example found in the book to populate the histogram array. It is very important that you manage to find the right spot for word length tracking (and resetting it) and histogram update.
You can create a function display_histogram for displaying the histogram afterwards.
Here's a code example:
#include<stdio.h>
#define MAX_WORD_LENGTH 15
#define IS_WORD_SEPARATOR_CHAR(c) (c == '\n' || c == ' ' || c == '\t')
#define IN 1
#define OUT 0
/* WARNING: There is no check for MAX_WORD_LENGTH */
void display_horizontal_histogram(int[]);
void display_vertical_histogram(int[]);
void display_histogram(int[], char);
void display_histogram(int histogram[], char type) {
if (type == 'h') {
display_horizontal_histogram(histogram);
} else if (type = 'v') {
display_vertical_histogram(histogram);
}
}
void display_horizontal_histogram(int histogram[]) {
printf("\n");
//ignoring 0 length words (i = 1)
for (int i = 1; i <= MAX_WORD_LENGTH; ++i) {
printf("%2d: ", i);
for (int j = 0; j < histogram[i]; ++j) {
printf("*");
}
printf("\n");
}
printf("\n\n");
}
void display_vertical_histogram(int histogram[]) {
int i, j, max = 0;
// ignoring 0 length words (i = 1)
for (i = 1; i <= MAX_WORD_LENGTH; ++i) {
if (histogram[i] > max) {
max = histogram[i];
}
}
for (i = 1; i <= max; ++i) {
for (j = 1; j <= MAX_WORD_LENGTH; ++j) {
if (histogram[j] >= max - i + 1) {
printf(" * ");
} else {
printf(" ");
}
}
printf("\n");
}
for (i = 1; i <= MAX_WORD_LENGTH; ++i) {
printf(" %2d ", i);
}
printf("\n\n");
}
int main()
{
int c, state, word_length;
int histogram[MAX_WORD_LENGTH + 1];
for (int i = 0; i <= MAX_WORD_LENGTH; ++i) {
histogram[i] = 0;
}
word_length = 0;
state = OUT;
while ((c = getchar()) != EOF) {
if (IS_WORD_SEPARATOR_CHAR(c)) {
state = OUT;
if (word_length != 0) {
histogram[0]++;
}
histogram[word_length]++;
word_length = 0;
} else {
++word_length;
if (state == OUT) {
state = IN;
}
}
}
if (word_length > 0) {
histogram[word_length]++;
}
display_histogram(histogram, 'h');
display_histogram(histogram, 'v');
}
Here's an input/output sample:
kaldklasjdksla klsad lask dlsk aklsa lkas adç kdlaç kd dklask las kçlasd kas kla sd saçd sak dasças sad sajçldlsak dklaa slkdals kkçl askd lsak lçsakç lsak lsak laskjl sa jkskjd aslld jslkjsak dalk sdlk jsalk askl jdsj dslk salkoihdioa slk sahoi hdaklshd alsh lcklakldjsalkd salk j sdklald jskal dsakldaksl daslk
1: *
2: ***
3: ******
4: ***************
5: **********
6: ****
7: ****
8: ***
9:
10: *
11: **
12:
13:
14: **
15:
*
*
*
*
*
* *
* *
* *
* *
* * *
* * *
* * * * *
* * * * * * *
* * * * * * * * *
* * * * * * * * * * *
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
You should separate your 2 problems in functions, like:
void gethist(char *s, int *hist, int len)
{ /* words here breaks on spaces (' ') */
char *t;
for( t=strtok(s," ");t;t=strtok(0," ") )
if(*t)
hist[ strlen(t)>len-1?len-1:strlen(t)-1 ]++;
}
void outhist(int *hist, int len)
{
int i;
for( i=1; i<=len; ++i )
{
char *s = calloc(1,5+hist[i-1]);
sprintf(s,"%03d|", i);
memset( s+4, 'X', hist[i-1]);
puts(s);
free(s);
}
}
then its easy in your main:
int main(void)
{
int c, hist[11] = {};
char *s = calloc(1,1);
while ((c = getchar()) != EOF) {
s = realloc( s, 2+strlen(s) );
s[ strlen(s)+1 ] = 0;
s[ strlen(s) ] = c;
}
gethist(s,hist,11); free(s);
outhist(hist,11);
return 0;
}
The vertical histogram can be printed one line at a time, by going through the array of word lengths and decreasing the word length at each iteration. A # is printed if the word length is still above zero, and a space is printed when it reaches 0. The newline is printed after each iteration.
If lengths[i] holds the number of characters for word i, and wordn is the total number of words, then the following will print the vertical histogram:
#define YES 1
#define NO 0
more_lines = YES;
while (more_lines)
{
more_lines = NO;
for (i = 1; i <= wordn; ++i)
{
if (lengths[i] > 0 )
{
more_lines = YES;
printf("#\t");
--lengths[i];
}
else
printf(" \t");
}
putchar('\n');
}
The complete code is below:
#include<stdio.h>
/* Prints a histogram of the lenghts of words */
#define MAX_WORDS 100
#define IN 1
#define OUT 0
#define YES 1
#define NO 0
main()
{
int c, length, wordn, i, j, state, more_lines, lengths[MAX_WORDS];
wordn = length = 0;
state = OUT;
for (i = 0; i < MAX_WORDS; ++i) lengths[i] = 0;
while ((c = getchar()) != EOF && wordn < MAX_WORDS)
{
if (c == ' ' || c == '\t' || c == '\n')
state = OUT;
else if (wordn == 0)
{
state = IN;
++wordn;
++length;
}
else if (state == IN)
++length;
else if (state == OUT)
{
lengths[wordn] = length;
++wordn;
length = 1;
state = IN;
}
}
lengths[wordn] = length;
/* Print histogram header */
for (i = 1; i <= wordn; ++i)
printf ("%d\t", i);
putchar('\n');
more_lines = YES;
while (more_lines)
{
more_lines = NO;
for (i = 1; i <= wordn; ++i)
{
if (lengths[i] > 0 )
{
more_lines = YES;
printf("#\t");
--lengths[i];
}
else
printf(" \t");
}
putchar('\n');
}
}
Although the exercise is based on Arrays, I tried to write it using the basic while loop and an if statement. I am not really good with Arrays as of now, so thought of trying this out. I have not tested it for bugs though, but it seems to be working fine for most inputs.
#include<stdio.h>
main() {
long int c;
while((c=getchar())!=EOF) {
if(c!=' '&&c!='\n'&&c!='\t') {
putchar("*");
}
if(c==' '||c=='\n'||c=='\t') {
putchar('\n');
}
}
return 0;
}
Please note that this is a very basic piece of code to print it horizontally, just for the basic understanding of the structure.
// Histogram to print the length of words in its input
#include <stdio.h>
main()
{
int wordcount[10],c,token=0;
int word=0, count =0;
for (int i=0; i<10; i++)
{
wordcount[i]=0;
}
while((c=getchar())!=EOF)
{
if(c== ' ' || c == '\n' || c== '\t')
{
// add the length of word in the appropriate array number
switch(word)
{
case 1:
++wordcount[0];break;
case 2:
++wordcount[1];break;
case 3:
++wordcount[2];break;
case 4:
++wordcount[3];break;
case 5:
++wordcount[4];break;
case 6:
++wordcount[5];break;
case 7:
++wordcount[6];break;
case 8:
++wordcount[7];break;
case 9:
++wordcount[8];break;
case 10:
++wordcount[9];break;
}
word =0;
}
else if (c != ' ' || c != '\n' || c!= '\t')
{
word++;
}
}
for (int j=0; j<10; j++)
{
if(wordcount[j]==0)
{
printf("- ");
}
for (int k=0;k<wordcount[j];k++)
printf("X", wordcount[j]);
printf("\n");
}
}
Here is the example of simple vertical Histogram
#include <stdio.h>
int main()
{
int c, i, j, max;
int ndigit[10];
for (i = 0; i < 10; i++)
ndigit[i] = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
max = ndigit[0];
for (i = 1; i < 10; ++i) /* for Y-axis */
if (max < ndigit[i])
max = ndigit[i];
printf("--------------------------------------------------\n");
for (i = max; i > 0; --i) {
printf("%.3d|", i);
for (j = 0; j < 10; ++j)
(ndigit[j] >= i) ? printf(" X ") : printf(" ");
printf("\n");
}
printf(" ");
for (i = 0; i < 10; ++i) /* for X-axis */
printf("%3d", i);
printf("\n--------------------------------------------------\n");
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
//hold length of string
unsigned long length;
// Holds the name input by user upto 50 characters
char name[50];
//iterator for generating dash for bar chart
int i = 0;
//iterator for generating dash for bar chart
int j = 0;
//take user name input
printf("input your name [without spaces and < 50 characters] : ");
scanf("%s", &name[0]);
//find the length of string
length = strlen(name);
printf("length of your name is %lu \n", length);
//generate dashes for bar chart
while (i < length)
{
printf("--");
++i;
}
printf("| \n");
// fill the bar chart with []
while (j < length)
{
printf("[]");
++j;
}
printf("| \n");
//generate dashes for bar chart
while (length > 0)
{
printf("--");
--length;
}
printf("| \n");
}
input your name [without spaces and < 50 characters] : ThisIsAtestRun
length of your name is 14
----------------------------|
[][][][][][][][][][][][][][]|
----------------------------|
I've tried to implement the latter part of the question (i.e. Displaying the histogram in a vertical manner) and have managed to get most of it done. In the code below, The maximum number of words accepted are 20 and the maximum word length is 10. Also, apologies for not getting the best graphical representation of a typical histogram but the logic to display vertical bars is completely accurate!
Here's my code,
#define MAXWORDS 20
#define MAXLENGTH 10
int c, nlength = 0, i, nword = 0, j;
int length_words[20]= {0};
while((c = getchar()) != EOF && nword <= MAXWORDS)
{
if(c != ' ' && c != '\t' && c != '\n')
++nlength;
else
{
if(nlength != 0){
length_words[nword] = nlength;
++nword;
/* for(i = 0; i < nlength; i++)
printf("O");
printf("\n");*/
printf("Word number: %d has length: %d\n", nword - 1, nlength);
}
nlength = 0;
}
}
// Displaying the Histogram
for(i = MAXLENGTH; i > 0; i--)
{
for(j = 0; j < nword; j++)
{
if(i > length_words[j])
printf(" ");
else
printf(" O ");
}
printf("\n");
}
Feel free to run this and let me know in case of any discrepancy or loopholes!
#include <stdio.h>
int main(void)
{
int i, ii, state, c, largest, highest;
int A[100];
for(i = 0; i < 100; ++i)
A[i] = 0;
i = ii = state = c = largest = 0;
while((c = getchar()) != EOF)
{
if(c == ' ' || c == '\b' || c == '\n')
{
if(state)
{
++A[i];
if(largest <= i)
largest = i;
i = state = 0;
}
}
else
{
if(state)
++i;
else
state = 1;
}
}
for(i = 0; i < 100; ++i)
if(highest <= A[i])
highest = A[i];
for(i = 0; i <= highest; ++i)
{
for(ii = 0; ii < 100; ++ii)
if(A[ii])
{
if(A[ii] > (highest - i))
printf("*\t");
else
printf(" \t");
}
putchar('\n');
}
for(ii = 0; ii < 100; ++ii)
if(A[ii])
printf("-\t");
putchar('\n');
for(ii = 0; ii < 100; ++ii)
if(A[ii])
printf("%d\t", ii + 1);
putchar('\n');
return 0;
}
Print Histogram based on word Length. (C Program).
HORIZONTAL VERSION :
#include<stdio.h>
#define MAX 15
int main()
{
int c, wordLength, count;
int arr[MAX] = { 0 };
wordLength = count = 0;
while((c = getchar()) != EOF)
{
if(c != ' ' && c != '\t' && c != '\n')
++arr[count];
else
++count;
}
for(int i = 0; i <= count; i++)
{
printf("\n%2d |", i+1);
for(int k = arr[i]; k > 0; k--)
printf("— ");
}
return 0;
}
Input/Output :
man in black thor jsjsk ksskka
1 |— — —
2 |— —
3 |— — — — —
4 |— — — —
5 |— — — — —
VERTICAL VERSION :
#include<stdio.h>
#define MAX 15
int main()
{
int c, count, maxLength;
int arr[MAX] = { 0 };
maxLength = count = 0;
while((c = getchar()) != EOF)
{
if(c != ' ' && c != '\t' && c != '\n')
++arr[count];
else
++count;
if(arr[count] > maxLength)
maxLength = arr[count];
}
for(int i = 1; i <= maxLength + 2; i++)
{
printf("\n");
for(int k = 0; k <= count; k++)
{
if(i <= maxLength)
{
if(maxLength - i < arr[k])
printf("|");
else
printf(" ");
}
else
{
if(maxLength - i == -1)
printf("—");
else
printf("%d", k+1);
}
printf(" ");
}
}
return 0;
}
Input/Output :
jsjs sjsj sjsj sjskks sjs sjs
|
|
| | | |
| | | | | |
| | | | | |
| | | | | |
— — — — — —
1 2 3 4 5 6
here is the method that I used :
#include <stdio.h>
#define MAXWD 25 // maximum words
#define MAXLW 20 // maximum lenght of word or characters
int main(void) {
int word[MAXWD]; // an array consists of 25 words
int c, i, j, nc, nw; // declaring c for the input, i for the loop 'for', j is for printing left to right, nc and nw stands for new character and new word
for (i = 0; i < 25; ++i)
word[i] = 0;
nc = nw = 0; // set to count from 0
while ((c = getchar()) != EOF) {
++nc;
if ( c == ' ' || c == '\t' || c == '\n') {
word[nw] = nc -1; // for deleting the space to go for the new word
++nw;
nc = 0; // start counting from zero
}
}
for (i = MAXLW; i >= 1; --i) {
for(j = 0; j <= nw; ++j) { // to start from left to wright
if (i <= word[j]) // MAXLW is less or equal to the number of words
putchar('|');
else
putchar(' ');
}
putchar ('\n');
}
return 0;
}
I'm trying to determine if a phrase is a palindrome (a word that is the same from left to rigth) or not but i can't make it work. What's wrong?, i can't use pointers or recursion or string type variables
#include <stdio.h>
#include <string.h>
int main()
{
int i,j = 0,length;
char space = ' ';
char phrase [80],phrase2[80],phrase3[80];
printf("Give me the phrase: ");
gets(phrase);
length = strlen(phrase);
for(i =0; i <= length - 1; i++)
{
if(phrase[i] != space) //Makes the phrase without spaces
{
phrase2[i] = phrase[i];
j++;
}
}
for(i = length -1; i >= 0;i--)
{
if(phrase[i] != space) //Makes the phrase backwards an without spaces
{
phrase3[j] = phrase[i];
j++;
}
}
length = strlen(phrase2);
for(i =0; i <= length -1;i++) //Compare the phrases to know if they are the same
{
if(phrase2[i] != phrase3[i])
{
printf("It's not a palindrome\n");
return 0;
}
}
printf("It's a palindrome\n");
return 0;
}
Try this:
for(i =0, j=0; i <= length - 1; i++)
{
if(phrase[i] != space) //Makes the phrase without spaces
{
phrase2[j] = phrase[i];
j++;
}
}
for(i = length -1, j = 0; i >= 0;i--)
{
if(phrase[i] != space) //Makes the phrase backwards an without spaces
{
phrase3[j] = phrase[i];
j++;
}
}
length = j;
Update
In response to Praetorian's post here's the code to do it without copying the string.
#include <stdio.h>
#include <string.h>
int main()
{
int i, j, length;
char space = ' ';
char phrase[80];
printf("Give me the phrase: ");
gets(phrase);
length = strlen(phrase);
for( i = 0, j = length - 1; i < j; i++, j-- ) {
while (phrase[i] == space) i++;
while (phrase[j] == space) j--;
if( phrase[i] != phrase[j] ) {
printf("It's not a palindrome\n");
return 0;
}
}
printf("It's a palindrome\n");
return 0;
}
Before the 2nd loop you want to set j=0. It should work after that.
PS: If you debugged by printing out your three strings, you would've figured it out in a matter of minutes. When you don't know what goes wrong, print out the values of variables at intermediate steps, so you know where your problem occurs and what it is.
Your question has already been answered by others but I'm posting this code to show that it is not necessary to make the phrase3 copy to hold the reversed string.
#include <stdio.h>
#include <string.h>
int main()
{
int i, j, length, halfLength;
char space = ' ';
char phrase1[80], phrase2[80];
printf("Give me the phrase: ");
gets(phrase1);
length = strlen(phrase1);
for( i = 0, j = 0; i <= length; ++i ) {
if( phrase1[i] != space ) { //Makes the phrase1 without spaces
phrase2[j++] = phrase1[i];
}
}
length = strlen(phrase2);
halfLength = length / 2;
for( i = 0, j = length - 1; i < halfLength; ++i, --j ) {
if( phrase2[i] != phrase2[j] ) {
printf("It's not a palindrome\n");
return 0;
}
}
printf("It's a palindrome\n");
return 0;
}
This is what I came up with:
#include <stdio.h>
void main() {
char a[50],b[50];
int i=0,j,ele,test=0,x;
while((a[i]=getchar())!='\n') {
if(a[i]!=' ' && a[i]!=',') //do not read whitespaces and commas(for palindromes like "Ah, Satan sees Natasha")
i++;
}
a[i]='\0';
ele=strlen(a);
// Convert string to lower case (like reverse of Ava is avA and they're not equal)
for(i=0; i<ele; i++)
if(a[i]>='A'&&a[i]<='Z')
a[i] = a[i]+('a'-'A');
x = ele-1;
for(j=0; j<ele; j++) {
b[j] = a[x];
x--;
}
for(i=0; i<ele; i++)
if(a[i]==b[i])
test++;
if(test==ele)
printf("You entered a palindrome!");
else
printf("That's not a palindrome!");
}
Probably not the best way for palindromes, but I'm proud I made this on my own took me 1 hour :( lol
Why not use a std::stack? You will need two loops, each iterating the length of the input string. In the first loop, go through the input string once, pushing each character ont the stack. In the second loop, pop a character off the stack and compare it with the character at the index. If you get a mismatch before the loop ends, you don't have a palindrome. The nice thing with this is that you don't have to worry about the even/odd length corner-case. It will just work.
(If you are so inclined, you can use one stack (LIFO) and one queue (FIFO) but that doesn't substantially change the algorithm).
Here's the implementation:
bool palindrome(const char *s)
{
std::stack<char> p; // be sure to #include <stack>
for(int i = 0; s[i] != 0; i++)
p.push(s[i]);
for(int i = 0; s[i] != 0; i++)
{
if(p.top() != s[i])
return false; // not a palindrome!
p.pop();
}
return true;
}
Skipping spaces is left as an exercise to the reader ;)