Debugging a histogram in C - c

First question here on Stack Overflow so forgive me if this is offtopic or not per etiquette, but it seems like it should be fine. I'm doing exercise 1-13 in K&R, specifically printing a vertical histogram of the length of words in an input. Here's my code so far:
#include <stdio.h>
#define UPPER 10
#define ABOVE (UPPER+1)
main()
{
int i, c, wcounter, j;
int wlengths[ABOVE];
int maxHistHeight;
for (i = 0; i <= ABOVE; ++i) /* Initialize everything to zero */
wlengths[i] = 0;
wcounter = maxHistHeight = 0;
while((c = getchar()) != EOF){ /* Count word lengths */
if (c != ' ' && c != '\t' && c != '\n'){
++wcounter;
}
else if (wcounter >= ABOVE){
++wlengths[ABOVE];
wcounter = 0;
}else if (wcounter != 0){
++wlengths[wcounter];
wcounter = 0;
}
}
for (i = 1; i <= ABOVE; ++i) /*For testing purposes. See if the array is holding correct values*/
printf(" %d ",wlengths[i]);
printf("\n");
for (i = 1; i <= ABOVE; ++i) /*Get the Maximum height for histogram */
if (wlengths[i]>maxHistHeight)
maxHistHeight = wlengths[i];
printf("Histogram of length of words\n"); /* Print histogram */
printf("----------------------------\n");
for (i = maxHistHeight; i >= 0; --i){ /* Start at top of histogram, and go downwards */
printf("\n");
for (j = 1; j <= ABOVE; ++j){ /*For each level of histogram, go through all the */
if (i == 0 && j != ABOVE){ /*Arrays, and see if they contain an X in that level */
printf(" %d ", j);
}else if (i == 0 && j == ABOVE){
printf(">%d",UPPER);
}
else if (wlengths[j]>=i){
printf(" X ");
}
else{
printf(" ");
}
}
}
printf("\n");
}
I want to print a histogram of the length of words that are 1-10 letters long, and also that are greater than 10 letters. I want it to look like this:
Histogram of length of words
X
X X X
1 2 3 4 5 6 7 8 9 10 >10
I'm using an array that is size 12 (not sure if this is how you would say it), with the 11th index holding all occurrences of words greater than 10 letters long. However, when I print out the histogram, it prints out an "X" in the >10 spot even if the word is only 10 letters long. So if I input this:
1234567890
123457890
1234567890
I get:
Histogram of length of words
----------------------------
X X
X X X
1 2 3 4 5 6 7 8 9 10 >10
I thought there must've been something with wrong with the way I was incrementing my array, so I printed the values of the array and got this:
0 0 0 0 0 0 0 0 1 2 0
which doesn't match what my histogram is printing. I appreciate any help!
UPDATE TO ORIGINAL QUESTION
So I fixed my array size to hold 12 elements: 10 for holding words with length 1-10, 1 for all words with length >10, and 1 for index 0, so that my index numbers match up with my word lengths. Before I had an array with just 11 elements,when I needed it to be 12, but when i printed out the values of my array, it displayed the correct values but during the printing of the histogram, it was incorrect. so given an input of this:
1234567890
1234567890
12345678901234567890
12345
I got this in the array (i'm printing from index 1 to index 11), and its correct:
0 0 0 0 1 0 0 0 0 2 1
But the histogram printout is different:
Histogram of length of words
----------------------------
X X
X X X
1 2 3 4 5 6 7 8 9 10 >10
Shouldn't they both be the same?

You array has dimension ABOVE (= 11) but you're iterating from 0 to ABOVE (inclusive) which is ABOVE + 1 (= 12) elements. The valid index range is only 0 to ABOVE - 1 so you're writing (and subsequently reading) beyond the end of the allocated array.
E.g. your initialisation loop should be:
for (i = 0; i < ABOVE; ++i) /* Initialize everything to zero */
wlengths[i] = 0;
I think you're probably getting muddled because C array indexes start at 0, while your histogram needs to represent word lengths from 1 to 10 and then 11 for word lengths > 10. You can approach this in one of two ways, either:
(a) adjust for the difference of 1, so words of length 1 go in bin 1, words of length 2 go in bin 1, etc, or
(b) allocate an additional element (i.e. make the array one element bigger than it needs to be) and simply don't use element 0. That way you don't have to worry about the offset of 1.

Lengths:
If you declare an array as
things[LEN]
then the array can hold LEN things.
Indexes:
But the array elements are indexed from
0 through LEN-1
and are accessed as
things[0], things[1], ..., things[LEN - 1]
So you'll commonly see loops looking like this:
for (i = 0; i < LEN; i++) {
do something with thing[i];
}
The problem is that you want word lengths from 1 to 10, so you need to
adjust the array indices accordingly.

Okay, I think I see what you guys meant. My array needs to be able to store 12 elements, assuming that I use indices 1-10 for word lengths 1-10, index 11 for all those word lengths >10, and finally, index 0 is discarded because I want the index numbers to line up with my word lengths. I set my array size to 12, or 2 more than my UPPER constant, and that seems to have done the trick. Here's my output:
Histogram of length of words
----------------------------
X
X X X
1 2 3 4 5 6 7 8 9 10 >10
given this input:
1234567890
1234567890
12345
12345678901234567890

Related

What should I do for sort array?

I tried to sort arr by excluding those who were already selected as the largest numbers but it didn't work.
The result is this:
As I intended, at first cycle, the store is {9, 0, 0, 0, 0 ... } and when arr[i] becomes 9, the rest of process should be skipped. I have to sort it without additional functions and it's too difficult to me. What is the problem?
int i = 0;
int j = 0;
int num = 0;
int sign = 0;
int arr[10] = { 1,5,3,4,8,7,5,9,8,0 };
int max = arr[0];
int store[10] = { 0 };
int k = 0;
for (j = 0; j < 10; j++) {
printf("store: ");
for (int n = 0; n < 10; on++)
printf("%d ", store[n]);
printf("\n");
for (i = 0; i < 10; i++) {
sign = 0;
k = 0;
while (k < 10) {
if (arr[i] == store[k]) {
sign = 1;
break;
}
k++;
}
if (sign == 1) {
continue;
}
if (arr[i] > max) {
max = arr[i];
}
}
store[j] = max;
}
You have several errors here:
The array store has a size of 10, but in the jth pass through the outer loop, only j values have been filled in; the rest is still zero. So whenever you iterate over store, you should use j as upper limit.
You are looking for the max in each iteration. Therefore, it is not enough to initialise max once outside the outer loop. You do that, and it will stay 9 ever after. You should reset max for every j.
Finally, your idea to go through the array to see whether you have already processed a certain value does not work. Your array has duplicates, two 8's and two 5's. You will only place one eight and one five with your strategy and re-use the last value of max for the last two elements. (Plus, that idea lead to O(n³) code, which is very wasteful.
You can work around that by keeping an extra array where you store whether (1) or not (0) you have already processed a value at a certain index or by setting processed entries in the array to a very low value.
What you want to implement is selection sort: Find the maximum value in the whole list and move it to the front. Then find the maximum in the whole list except the first item and move it to the second slot and so on:
* 1 5 3 4 8 7 5 9 8 0
9 * 5 3 4 8 7 5 1 8 0
9 8 * 3 4 5 7 5 1 8 0
9 8 8 * 4 5 7 5 1 3 0
9 8 8 7 * 5 4 5 1 3 0
9 8 8 7 5 * 4 5 1 3 0
9 8 8 7 5 5 * 4 1 3 0
9 8 8 7 5 5 4 * 1 3 0
9 8 8 7 5 5 4 3 * 1 0
9 8 8 7 5 5 4 3 1 * 0
9 8 8 7 5 5 4 3 1 0 *
Here, all items to the left of the asterisk have been sorted and everything to the right of the asterisk is still unsorted. When the * (at position j) has moved to the right, the whole array is sorted.
This sort is in-place: It destroys the original order of the array. That is useful, because the position of an element tells us whether it has been processed or not. In the third iteration, the algorithm can distinguish between the 8 that has been sorted and the 8 that hasn't been sorted yet. (This sort is often described as sorting a hand of cards: Look fo the lowest, put it to the left and so on. If you must sort into a second array, copy the original array and sort the copy in place.)
Here's the code that sorts your array and prints out the diagram above:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int arr[10] = {1, 5, 3, 4, 8, 7, 5, 9, 8, 0};
int i = 0;
int j = 0;
for (j = 0; j < 10; j++) {
int imax = j;
int swap = arr[j];
// print array
for (i = 0; i < 10; i++) {
if (i == j) printf("* ");
printf("%d ", arr[i]);
}
printf("\n");
// find index of maximum item
for (i = j + 1; i < 10; i++) {
if (arr[i] > arr[imax]) {
imax = i;
}
}
// swap first unsorted item and maximum item
arr[j] = arr[imax];
arr[imax] = swap;
}
// print fully sorted array
for (i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("*\n");
return 0;
}
Use i and j.
N is 10 and the data consists of shuffled numbers 0 to N-1.
j goes from 0 to N-1. At each step, you want to fill it with
the maximum of the unprocessed input.
So i goes from j+1 to N-1, in the inner loop. If arr[j] < arr[i],
swap arr[i] and arr[j].
It speeds up considerably as you get towards the end.

Count alphabets in C using log functions(without math.h) and arrays

I'm facing a slight problem with one of my projects. I am supposed to write a c program to calculate each character present in the input/file. (It's supposed to be a basic program.) The constraints - I cannot use the math.h library to produce log functions and obtain an output in the format:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
The program is supposed to count the number of occurrences of each alphabetic letter (case insensitive) in the stdin input stream and display a histogram.
As you can see, the output is formatted vertically with each line printing the base 10 number of the position of the character.
Now, this might seem silly, but what I have so far is this:
#include <stdio.h>
#include <ctype.h>
/*
int logBase10 (int num) {
method to calculate the log base 10 of num
}
*/
int main (int argc, char * argv[]) {
char alpha;
int count = 0;
int ascii[128] = {0};
while ( (alpha = getchar()) != EOF) {
count++;
ascii[(int)alpha]++;
alpha = getchar();
}
printf("Char \t Count \n");
printf("------------------------\n");
for (int i = 0; i < 127; i++) {
if(ascii[i] > 0) {
printf("%c \t %d \n", i, ascii[i]);
}
}
}
Which produces an output like this:
Char Count
------------------------
5
93
, 6
- 2
. 3
; 2
C 2
I 6
N 1
T 1
W 2
a 26
b 5
c 8
d 13
e 55
f 11
g 7
h 28
i 32
k 3
l 26
m 17
n 31
o 27
p 12
q 1
r 26
s 22
t 42
u 11
v 8
w 8
y 13
z 1
First off, my program is printing unwanted ascii characters (, ; - etc) and I am working on changing the print function to be more vertical, but I cannot figure out the log method at all. I know log(10) is 1 because 10^1 is 1, but I am having trouble figuring out how to use this to create the method itself. Also, for the extra characters, I tried using:
if(ascii[i] > 65 || ascii[i] < 90 || ascii[i] >= 97 || ascii[i] <= 122 ) {
printf("%c \t %d \n", i, ascii[i]);
}
to no avail. Trying that produced more gibberish characters instead.
Any help/feedback is appreciated.
Soul
The commenters have already pointed out issues with your code. Here's a version that counts only letters and prints vertical labels. It doesn't need <ctype.h> or <math.h>.
Each character hets a letter index which is a number from 0 to 25 for upper and lower case letters and −1 if the character isn't a letter. That reduces the array size to 26.
You could find out each digit with elaborate calculations, but the easiest way is to print the number to a string. snprintf does this for you. You can right-align the number with a field width. The maximum value for a typical int is about 2 billion, which has 10 digits. You should account for that, even if you had to pass in the whole Moby-Dick plus the Bible to get that many counts.
You can test whether you should start printing by assuming a width of ten digits first and checking whether the maximum count has ten digits, that is whether it is 1,000,000,000 or higher. Then divide that limit by 10 in each iteration.
Here's the code:
#include <stdio.h>
// return letter index or -1 for non-letter
int letter(int c)
{
if ('a' <= c && c <= 'z') return c - 'a';
if ('A' <= c && c <= 'Z') return c - 'A';
return -1;
}
int main(int argc, char * argv[])
{
int count[26] = {0}; // letter counts
char label[26][12]; // buffer for printing numbers
int limit = 1000000000; // smallest 10-digit number
int max = 0;
int i, j;
// read and count letters
while (1) {
int c = getchar();
if (c == EOF) break;
c = letter(c);
if (c >= 0) count[c]++;
}
// write auxiliary labels
for (i = 0; i < 26; i++) {
snprintf(label[i], sizeof(label[i]), "%10d", count[i]);
if (count[i] > max) max = count[i];
}
// print vertical labels
for (j = 0; j < 10; j++) {
if (max >= limit) {
for (i = 0; i < 26; i++) {
putchar(' ');
putchar(label[i][j]);
}
putchar('\n');
}
limit /= 10;
}
// print horizontal rule
for (i = 0; i < 26; i++) {
putchar('-');
putchar('-');
}
putchar('-');
putchar('\n');
// print letters
for (i = 0; i < 26; i++) {
putchar(' ');
putchar('A' + i);
}
putchar('\n');
return 0;
}
On your example, it produces:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
-----------------------------------------------------
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
One easy way to figure out how many digits that you'll need is to use sprintf to convert the integer count to a string, and then use strlen to find out how many digits you have. For example:
char str[20] = {0}; // 20 digits should be enough for your case
for (i = 0; i < 128; i++) {
sprintf(str, "%d", ascii[i]);
num_digits = strlen(str);
printf("%d has %d digits\n", ascii[i], num_digits);
}
I didn't test the code, but it should be close.
Some pseudo code
Find max count
Find width of that count when printed w=sprintf(buf, "%d", mxcnt)
Loop w times (wi = 0 to w - 1)
for each non-zero count
form string sprintf(buf, "%*d", w, count[i])
print buf[wi] character
print space
print \n

Calculating total number of adjacent integers

I want to calculate the number of integers excluding repeats line by line from the file.
The output I desire is:
Duplicates : 9
Duplicates : 4
Duplicates : 5
Duplicates : 5
Duplicates : 1
Duplicates : 1
Duplicates : 8
For further explanation of the concept:
Take the second line of the file:
1 2 3 4 5 6 5 4 5
At this line there is a 1 so increment the counter because 1 was found first.
Next comes a 2, 2 is not 1 so increment the counter. Next comes a 3, 3 is not a 2 so increment the counter. Next comes a 4, 4 is not a 3 so increment the counter. Next comes a 5, 5 is not a 4 so increment the counter. Next comes a 6, 6 is not a 5 so increment the counter. Next comes a 5, 5 is not a 6 so increment the counter. Next comes a 4, 4 is not a 5 so increment the counter. Next comes a 5, 5 is not a 4 so increment the counter. The number of integers excluding repeats is 9.
Another example:
Take a look a line 8 of the file:
34 34 34 34 34
At this line there is a 34 so increment the counter. Next comes a 34, 34 is 34 so do not increment the counter. Next comes 34, 34 is 34 so do not increment the counter. Next comes a 34, 34 is 34 so do not increment the counter. Next comes a 34, 34 is 34 so do not increment the counter. The number of integers excluding repeats is 1.
EDIT:
I took the suggestion of a user on here and looked at a few link related to adjacent strings and integers. The output is almost completely correct now when compared to the desired output that I listed above. I will only put the pertain code below:
Output:
check1:1
check1:1
check1:2
Duplicates : 6 (Wrong value)
check1:2
Duplicates : 5 (Wrong value)
Duplicates : 5
Duplicates : 5
check1:0
check1:0
check1:0
check1:0
Duplicates : 1
Duplicates : 1
check1:0
check1:0
check1:2
check1:3
check1:3
check1:3
check1:4
check1:5
check1:5
check1:5
check1:5
check1:6
check1:6
Duplicates : 7 (Wrong value)
From the output it appears that whenever a test case goes through the if statement if(array[check] == ch), the output is incorrect.
I have been staring at the loops in this function for a long and I am still stumped.
Any suggestions as to why that loop is leading to incorrect values? Thank you.
Your logic is too complicated, this simple logic should do it
Count the first value
Start a loop from the second value to the last
Subtract the current value from the previous, if the result is 0 then it's the same value, do not add to the counter otherwise add to the counter.
I wrote a program to show you how
numbers.txt
1 2 3 4 5 6 5 4 5
14 62 48 14
1 3 5 7 9
123 456 789 1234 5678
34 34 34 34 34
1
1 2 2 2 2 2 3 3 4 4 4 4 5 5 6 7 7 7 1 1
program.c
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
FILE *file;
char line[100];
file = fopen("numbers.txt", "r");
if (file == NULL)
return -1;
while (fgets(line, sizeof(line), file) != NULL)
{
char *start;
int array[100];
int count;
int value;
int step;
count = 0;
start = line;
while (sscanf(start, "%d%n", array + count, &step) == 1)
{
start += step;
count += 1;
}
fprintf(stderr, "%d ", array[0]);
value = 1;
for (int i = 1 ; i < count ; ++i)
{
value += (array[i] - array[i - 1]) ? 1 : 0;
fprintf(stderr, "%d ", array[i]);
}
fprintf(stderr, " -- %d\n", value);
}
fclose(file);
return 0;
}
You simply need to check the current value to previous value of the array and check if they are equal or not something like this ::
int ans = 1;
for (int i = 1 ; i < n ; i++) { //n is the number of elements in array
if (a[i] != a[i - 1]) {
ans++;
}
}
printf("%d", ans);
I do not exactly understand why you use so many check in your code. What I do in this code is that I check my current element in the array (starting from 1) and compare it with previous element, so if they are not equal you have a unique element in your array (sequentially), and hence I increment the ans which is the number of unique elements sequentially.
Here I start with ans = 1 because I assume that there will be at least 1 element in your array and that will be unique in any case.
I don't know what you are using that much code for.
But for what i understand you want to do, it a simple loop like this:
#include <stdio.h>
int main() {
int array[] = {1,3,5,7,9};
int count = 1;
int i = 0;
for(i=1; i<(sizeof(array)/sizeof(array[0])); i++) { //sizeof(array)/sizeof(array[0]) calculates the length of the array
if(array[i]!=array[i-1]) {
count++;
}
}
printf("%d", count);
}

iterative solution to permutation calculation in C

I'm working on a problem dealing with iteration. I'm supposed to pass in two ints into a function, which represent a number of N objects and M values that I must find all permutations of. I am also given a sample of what the output is supposed to look like
void perm_iter(int N, int nr_values)
and the output this is supposed to print is :
Called : perm_iter(3, 2);
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
I understand the concept of recursion by using a swap function to change the orders of strings to find all permutations of a string, but I'm unsure of how to use iteration to get the same, or similar result. Is this a case where I need to use the stack and push/pop iteratively to get my answer? I was thinking I could use something like a set of nested loops to take the place of recursion and get something like this output but I'm unsure how to set the loops up to go through every permutation and not just iterate, missing some of the possible permutations.
Any help would be appreciated, and thank you for your time.
You just need to count up each "digit" until the max is reached, then reset and increment the next.
Imagine nr_values is 10 (with n=2):
0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9
1 0
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
Looks familiar because it's just "regular" counting in this case.
Implement this just like you count up: In each step, increment the leftmost value. If max is reached, reset and increment the next value etc.
void perm_iter(int n, int nr_values) {
int[] counter = new int[n];
int i;
// Clear all values
for (i = 0; i < n; i++) {
counter[i] = 0;
}
do {
// Print the current set of values
for (i = 0; i < n; i++) {
printf("%n ", counter[i]);
}
printf("\n");
// Keep incrementing while the values overflow,
// starting at the rightmost counter
i = n - 1;
while (i >= 0) {
counter[i]++;
if (counter[i] < nr_values) {
break;
}
counter[i] = 0;
i--;
}
// We are done when the first value overflows
} while (i >= 0);
}

How do I print this pattern in C?

I have to print this:
0
1 0 1
2 1 0 1 2
3 2 1 0 1 2 3
4 3 2 1 0 1 2 3 4
5 4 3 2 1 0 1 2 3 4 5
My code:
#include<stdio.h>
int main()
{
int i,j,k,l;
for(i=1;i<=6;i++)
{
for(j=6;j>i;j--)
{
printf(" ");
}
for(k=i-1;k>=0;k--)
{
printf("%d",k);
}
for(l=1;l<i;l++)
printf("%d",l);
printf("\n");
}
return 0;
}
My output:
0
101
21012
3210123
432101234
54321012345
I have just started coding in C so this is new to me. How do I put space between numbers so that the final output looks more elegant than it currently is?
I tried %-6d in printf("%d",k); to adjust the width but it had wrong indentation of the output.
That's easily fixed. Everywhere that you currently print a character (other than the newline), simply print that character followed by a space.
If you do that, you'll see the output you desire:
0
1 0 1
2 1 0 1 2
3 2 1 0 1 2 3
4 3 2 1 0 1 2 3 4
5 4 3 2 1 0 1 2 3 4 5
I won't show you the code since it's almost certainly classwork and you'll be a better coder if you nut it out yourself. But I will give you the tidbit that there are three lines that need to change. That should be more than enough to get the issue solved.
As a side note, this will also print a space at the end of each line, after the final digit. If that's not allowed, there are ways to fix it, primarily by changing the final loop so it doesn't output a space for the final item on the line.
It will also start failing miserably if you start trying to use two-digit numbers. To solve that, you need to know the widest number and use printf fields specifiers with widths. However, since it wasn't in the original spec, I haven't implemented that (see YAGNI).
If you wanted to implement something like that (with both the larger numbers and removed space at line end), you could use something like:
#include<stdio.h>
#define COUNT 15
int main(void) {
// Sanity check.
if (COUNT < 1) return 0;
// Get maximum width.
int width = 1, value = COUNT;
while (value > 9) {
value /= 10;
width++;
}
// For each line.
for (int line = 1; line <= COUNT; line++) {
// Output leading spaces.
for (int column = COUNT; column > line; column--)
printf("%*s ", width, "");
// Output descending digits.
for (int column = line - 1; column >= 0; column--)
printf("%*d ", width, column);
// Output ascending digits.
for (int column = 1; column < line; column++) {
printf("%*d", width, column);
if (column < line - 1) putchar(' ');
}
// Finish off line.
putchar('\n');
}
return 0;
}
It has the following advantages:
it allows for variable widths.
it uses more appropriately named (and fewer) loop variables.
it doesn't output the space at the end of each line.
Just don't use it as is if this is classwork, you'll almost certainly be found out.
use this..
add one space in in all three loops.
int i, j, k, l;
for (i = 1; i <= 6; i++) {
for (j = 6; j > i; j--) {
System.out.printf(" ");
}
for (k = i - 1; k >= 0; k--) {
System.out.printf("%d ", k);
}
for (l = 1; l < i; l++) {
System.out.printf("%d ", l);
}
System.out.printf("\n");
}
Instead of printf("%d",k) use printf("%d ",k).

Resources