1

I recently started to learn C language and I'm currently trying to code a simple program which should return the number of times that a character has been used, but the output is wrong. Why doesn't it work properly? Any help will be really appreciated. Here's the code:

#include <stdio.h>

main() {
    int c, i;
    int ndigit[25]; //a = 97

    while( (c = getchar()) != EOF) {    
        ++ndigit[c - 97];
    }
    
    for (i = 0; i < 26; i++) {  
        putchar(i + 97);
        printf(" = %d\n", ndigit[i]);
    }
}

And here's the output with the word "hello":

a = 8
b = 0
c = 4203649
d = 0
e = 4202641
f = 0
g = 84
h = 1
i = 12260176
j = 0
k = 1
l = 2
m = -1
n = -1
o = 85
p = 0
q = 1
r = 0
s = 4203673
t = 0
u = 0
v = 0
w = 84
x = 0
y = 0
z = 0
E_net4
  • 27,810
  • 13
  • 101
  • 139
LollolCat
  • 23
  • 7
  • 3
    You're taking for granted that every character read by `getchar` is a lowercase alphabetic character, that your character set is ASCII – Govind Parmar Mar 20 '21 at 22:30
  • 3
    Instead of `c +/- 97` you should use `c +/- 'a'`. And your array is not initialized, which means that it contains random numbers. You should set all items to 0. – Devolus Mar 20 '21 at 22:30
  • 1
    you should initialize `ndigit` to size 26 – Superior Mar 20 '21 at 22:45
  • you coud use \`\`\`Your code \`\` to include your code without indenting it. –  Mar 20 '21 at 23:06

3 Answers3

3

When you make a new array it might contain random numbers. You need to manually set it to 0s. A way to do that is use the following function:

memset(ndigit,0,sizeof(int)*26);

You also need to include string.h to use that

Edit: Forgot that the array is type int so we need to multiply the size by the size of an int

Edit2: Also i think you want your array to have size 26

AlephRZS
  • 73
  • 6
3

Your problem is that your array may contain random values. In C/C++ you are not guarantied that memory is zeroed out at the start of the program, but rather you might get whatever was there before. As above stated you could use some built in function, but simply doing this:

int ndigit[26]; // as mentioned in comments and in previous answers English alphabet has 26 characters

for (int i = 0; i < 26; ++i)
   ndigit[i] = 0;

// rest of you code here

One more problem is in main you have to put return 0 for same reason as your array. Random value could be returned if you do not have return 0.

main () {
   // your code here

   return 0;
}

Per @superior you could also use

ndigit[26] = {0}

This is however C99 standard and come compilers which do not follow it strictly will not initialize array. I know gcc version prior to 4.xx did not.

EDIT: Here is my output with your (OP's code) with inputhello

a = 4543
b = 0
c = 0
d = 0
e = 1318238529
f = 32604
g = 121
h = 1
i = 37
j = 57
k = 1136
l = 2
m = 1
n = 0
o = 4195998
p = 0
q = 142
r = 0
s = 0
t = 0
u = 4195920
v = 0
w = 4195568
x = 0
y = -1400909520
z = 32767

Here is output of my answer, with for() loop, and suggested {0}.

a = 0
b = 0
c = 0
d = 0
e = 1
f = 0
g = 0
h = 1
i = 0
j = 0
k = 0
l = 2
m = 0
n = 0
o = 1
p = 0
q = 0
r = 0
s = 0
t = 0
u = 0
v = 0
w = 0
x = 0
y = 0
z = 0
  • He could also write int ndigit[26] = {0} which sets whole array to 0s – Superior Mar 20 '21 at 22:49
  • Lols, @Superior I appreciate your comment and will include it in my answer, I have to mention that this is C99 and till recently some compilers and some Linux distors were bit behind. –  Mar 20 '21 at 23:15
2

I'm currently trying to code a simple program which should return the number of times that a character has been used

That's a rather good starter exercise.

Some notes that will make it easier to get to results faster:

  • Use your compiler's ability to help you
    • If you are using gcc or clang: -stdc18 -Wall -Wextra -pedantic -pedantic-errors

What you will notice is that wour main() function is invalid. C doesn't allow type-less functions. A proper main needs to be returning int, implicitly or explicitly. If in doubt, just know that it will return 0 by default.

You also not initialize your array. That has consequences - like not nowing what will happen when reading from the memory.


A suggestion to fix the program is not to use magic numbers. It is a trap (assuming 97 will fall out of fashion long before 'a' will). Use 'a' - or better, use the constants in the C library.

Everything below here goes awry once unicode comes into play but it counts "bytes" values well.

#include <stdio.h>
#include <string.h>
#include <limits.h> /* UCHAR_MAX (almost never anything but 255) */

char friendlify(unsigned char x) { /* unsigned to char cast ... */
    /* this is just for presentation - purely ASCII friendly */
    /* ternary operator: (condition) ? (true) : (false) */
    return x < '.' || x > '~' ? '.' : x;
}

int main() {
    int c;
    /* make room for all `char`s (unsigned chars really) */
    unsigned ndigit[UCHAR_MAX+1] = {0}; /* zero initialize */

    while ((c = getchar()) != EOF) {
        /* since getchar returns an unsigned - (unless EOF) we're not worried here) */
        ++ndigit[c];
    }

    printf("Collected:\n");
    for (unsigned i = 0; i <= UCHAR_MAX ; ++i) {
        /* just print characters included in the input */
        if (ndigit[i]) { /* assuming zero hits aren't interesting */

            /* %02X and the `i` makes it print the hex value of that particular byte */
            printf("0x%02X  %c  Count = %u\n", i, friendlify(i), ndigit[i]);
        }
    }
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Good answer but I think `C doesn't allow type-less functions` does not apply for `main()`. By default it will return int. –  Mar 21 '21 at 01:56
  • @CEPB Thanks! But, regarding `main`: No, it will not. `main` needs to be declared `int` or else your program is invalid. – Ted Lyngmo Mar 21 '21 at 01:58
  • Is it included in C99? –  Mar 21 '21 at 01:59
  • @CEPB I stopped programming C ~98 :-) I live on past XP. I hope it didn't deteriorate while I was gone though. – Ted Lyngmo Mar 21 '21 at 02:01
  • 1
    LOL just found it, it is in `C99` and later standards, however ANSI C and gcc still allow functions to fly by w/o return type specified in which case it is `int`. https://stackoverflow.com/a/16136583/5550963 –  Mar 21 '21 at 02:06
  • 1
    @CEPB I think all C standard(s) allow for non-"standard (common)" implementation specific specialzations to allow for embedded perfections. Edit: I live on ideas from C++ - I may be totally wrong – Ted Lyngmo Mar 21 '21 at 02:09
  • @CEPB I tried moving this to a chat because of a prior post I recognized that we shared. That act isn'tt grand I know, but you left a final comment. It was about operator precedence / `iostream`s etc but it's locked - so I can't comment. I can't even move this to the chat section. – Ted Lyngmo Mar 21 '21 at 02:28
  • Chat does not work on SO. But, yeah that one, I try to simplify things as much as possible. But it sometimes blows into my face :). It's bit confusing for newby what LHO and RHO operand is. That's what I was avoiding. –  Mar 21 '21 at 03:00
  • @CEPB I've no doubt! I¨m personally struggling with references. `lho` and `lro` doesn't seem to cut it anymore. `operator<<` and `operator>>` still does though. :-) – Ted Lyngmo Mar 21 '21 at 03:10