CheetahBongos - 1 year ago 56
C Question

# Don't understand function to count digits in character array

I am having a lot of trouble understanding my professor's solution to a program that counts the number of digits in a character array.

``````int main(void)
{
char* s[] = {"12, 34, 56, 78",
"82.16, 41.296",
"2, -3, 5, -7, 11, -13, 17, -19",
"9.00009, 90.0009, 900.009, 9000.09, 90000.9"};
int i, rows = sizeof(s)/sizeof(s[0]);

for(i = 0; i < rows; i++) {
digitCounts( s[i] );
}
}

void digitCounts(char* s) {
int counts[10] = { 0 };
int i = 0;

while( s[i] != '\0' )
{
if('0' <= s[i] && s[i] <= '9')
counts[ s[i] - '0' ]++;

i++;
}

for(i = 0; i < 9; i++)
printf("%d, ", counts[i]);

printf("%d\n\n", counts[i]);
}
``````

``````while( s[i] != '\0' )
{
if('0' <= s[i] && s[i] <= '9')
counts[ s[i] - '0' ]++;

i++;
}
``````

I understand the while-loop conditional: if the element at s[i] is not equal to NUL, then proceed. But the if statement is confusing to me because are you comparing numerical values or string values? How can a string value be greater than or less than another? e.g. '1' <= '9'. Also, wouldn't the first element of s[] be '12'? Not '1'. In other words, it wouldn't be a single digit.

The line

``````if('0' <= s[i] && s[i] <= '9')
``````

is comparing individual characters within a single string against the character constants `'0'` and `'9'` (ASCII values 48 and 57).

Remember that a string in C is a sequence of character values followed by a 0-valued terminator, and string literals are delimited by double quotes (`"`). Strings (including string literals) are stored as arrays of `char`. Each element of `s` contains the address of the first character of an array of `char`, sort of like the following1:

``````   +---+         +---+---+---+
s: |   | ------> |'1'|'2'| 0 |
+---+         +---+---+---+
|   | ----+
+---+     |   +---+---+---+
|   | -+  +-> |'3'|'4'| 0 |
+---+  |      +---+---+---+
...   |
|      +---+---+---+
+----> |'5'|'6'| 0 |
+---+---+---+
``````

Thus, `s[0]` points to the string `"12"`, `s[1]` points to the string `"34"`, etc. Each `s[i]` is passed to the `digitCounts` function, which walks through the string character by character and checks each to see if it is a digit.

The C language definition guarantees that the values of the digit characters `'0'`, `'1'`, `'2'`, etc., are sequential, so any character value between `'0'` and `'9'` must be a digit character. So the condition

``````if ( '0' <= s[i] && s[i] <= '9' )
``````

is checking to see if each `s[i]` is a digit character (character constants like `'0'` and `'9'` are delimited by single quotes). Note that there is a library function that does this same thing, with the bonus that it takes locale into account:

``````#include <ctype.h>
...
if ( isdigit( s[i] ) ) // does the same thing as the line above.
``````

Your professor's code is ... not awesome. It would have been nice if he used different names for the array of strings in `main` (such as `numberStringList`) vs. the input parameter to `digitCounts` (such as `numberString`); I think that accounts for some of your confusion. And he should have shown you how to use the `isdigit` function instead of hand-hacking the check.

1. In `main`, `s` is declared as an array of pointer to `char` (`char *[]`). The size of the array is taken from the number of initializers in the initializer list.

Each string literal in the initializer is also an array of `char`, but under most circumstances array expressions are converted ("decay") to pointer expressions, and the value of the expression is the address of the first element of the array. So each `s[i]` stores the address of the string literal, not the literal itself.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download