1

I am trying to count the number of total characters, excluding spaces, in (what I believe) is a pointer to an array of strings, called myArray.

I am struggling to work out what is wrong. Any help would be much appreciated!

char *myArray[1000] = {"Oh! ", "Hello ", "world."};

int count = 0, x;

for (x = 1; x <= 1000; ++x) {
    count += strlen(myArray[x]);
}

printf(count);

Desired output:

14
8
  • 4
    two questions -- do arrays start with 1 or 0? And what happens when x = 5 in your for statement? Commented Feb 15, 2017 at 21:49
  • Obviously, you can't use strlen. What have you tried? What problem are you having? Commented Feb 15, 2017 at 21:49
  • 8
    @ikegami - he is showing us exactly what he tried and all you have to do is read it to know the problem(s) he is having. Commented Feb 15, 2017 at 21:50
  • 1
    @0andriy - string constants are null terminated so I don't know what you mean by point one. If he starts at zero and checks for null then I believe the only problem is counting the spaces. Commented Feb 15, 2017 at 22:05
  • 2
    @AdrianM. No, because the string literal locations are not necessarily in any logical sequence, so you cannot get the total length by computing from the pointer values. And that would not deal with not-to-be-counted spaces anyway. Commented Feb 15, 2017 at 22:22

4 Answers 4

6

Yuu can use standard functions from ctype.h to identify the character class. For example, using issspace() you can find if a character is a whitespace and if so, you can ignore it.

You are looping over indexes from 1 to 1000. Indexing in C starts from 0 and goes upto N-1. Besides, your contains only 3 pointers; rest are just NULL (implicitly zero initialized).

Another problem is you are printing count without a format specifier. count being int, you would need to use %d as format specifier. However, you can use size_t as that's the type string functions return and the type that can hold the largest object.

#include <stdio.h>
#include <ctype.h>

int main(void)
{

char *myArray[] = {"Oh! ", "Hello ", "world."};

size_t count = 0, x, y;

for (x = 0; x < sizeof(myArray)/sizeof(myArray[0]); x++) {
    for (y = 0; myArray[x][y]; y++) {
        count += (isspace((unsigned char)myArray[x][y]) == 0);
    }
}

printf("Total chars: %zu\n", count);
}
Sign up to request clarification or add additional context in comments.

4 Comments

"[size_t is] the type that can hold the largest object" That would be big enough for the length of one string, but it's storing the total size of many strings; size_t isn't necessarily big enough. Still preferable to int.
@Schwern size_t may not be to hold size of many strings. But I don't see how that's a justification to use int. At least, size_t avoids integer overflow and probably can hold larger values than int.
Yes, I agree it's better than int and is probably so enormous that code could never reach it. But size_t can still overflow. size_t size = SIZE_MAX; printf("%zu\n", size+1); is 0. It's not a practical problem, more about the perils using a type to add together numbers of the same type.
@Schwern That's not true. size_t can never overflow (just like all other unsigned integers). When size_t wraps around, it's at least incorrect result; whereas, when an int overflows, it's undefined behaviour which is certainly worse.
4

This code has a bunch of warnings. Unfortunately most C compilers do not issue warnings by default. Using -Wall turns on the most common warnings, though inexplicably not all of them.

That'll at least let you know that you're using printf incorrectly.

test.c:13:12: warning: incompatible integer to pointer conversion passing 'int' to parameter of type
      'const char *' [-Wint-conversion]
    printf(count);
           ^~~~~

printf takes a format string which tells it the type of the thing its turning into a string.

printf("%d\n", count);

The next problem is this for loop.

for (x = 1; x <= 1000; ++x) {

That counts from 1 to 1000. But arrays in C start at 0. For a 1000 element array, you want to go from 0 to 999 else you'll miss the first element and then walk off the end of the array.

for (x = 0; x < 1000; ++x) {

While myArray has been allocated memory on the stack, and its first few elements have been set to constant strings, everything after that will be NULL (if it were allocated with malloc they would be filled with garbage). Since you're iterating over all the elements you're passing null pointers to strlen which is causing a segfault. You have to stop at the first null. Putting a null pointer at the end of an array of pointers is a good way to know when to stop.

Finally, since myArray is full of pointers to constant strings, you should declare it a list of pointers to const char. That will quiet this warning that's telling you you might be trying to modify constant strings.

test.c:5:28: warning: initializing 'char *' with an expression of type 'const char [5]' discards
      qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    char *myArray[1000] = {"Oh! ", "Hello ", "world.", NULL};

Putting it all together...

#include <stdio.h>
#include <string.h>

int main() {
    const char *myArray[1000] = {"Oh! ", "Hello ", "world."};

    int count = 0, x;

    for (x = 0; myArray[x] != NULL; ++x) {
        count += strlen(myArray[x]);
    }

    printf("%d\n", count);
}

Now that we've got the basic loop working, we can replace strlen with something that's going to count the characters while skipping whitespace.

ctype.h has a bunch of functions for finding out what type a character is. We can use isspace to tell if a character is whitespace. But we're going to have to write our own function to loop through the string and examine all the characters.

There's a bunch of ways to loop through a string. We could get the length and iterate.

size_t len = strlen(string);
for( int i = 0; i < len; i++ ) {
    ...
}

But C doesn't store the length of a string. strlen has to do its own loop through the string until it sees a null byte, so really the above is looping through the string twice. We can do better and iterate through looking for the null byte ourselves.

Again, we could use a normal for loop and loop until we see a null byte.

for( int i = 0; string[i] != '\0'; i++ ) {
    ...
}

But we don't even need i. Instead, we can increment string directly, changing where the start of the string is, and always look at string[0].

int count_chars_without_spaces( const char *string ) {
    int count = 0;

    for( ; string[0] != '\0'; string++ ) {
        if( !isspace(string[0]) ) {
            count++;
        }
    }

    return count;
}

That's ok because string is a variable local to that particular function. We can change it without changing the string.

So plug that in instead of strlen and you're good!

10 Comments

He doesn't want to count spaces in his answer.
@TonyTannous There, I fixed it. I was too busy fixing everything else to notice the original question.
@Hogan: explain me why x < sizeof(myArray)/sizeof(myArray[0]) is wrong? it works and other answers just do the same...
@Jean-FrançoisFabre I'm not a fan of x < sizeof(myArray)/sizeof(myArray[0]) myself because it's of limited utility and new C coders will try to use it on heap memory and get confused. I'd rather techniques that work no matter how the array was allocated. But it isn't silly. You covered the issue of unnecessarily allocating 1000 places, that's good. As for the downvoting, I got downvoted and it helped me realize I'd missed something. And then I fixed mine. ¯_(ツ)_/¯
@Jean-FrançoisFabre -- I've no idea where my comment went, I guess it was deleted by a moderator? Strange. I may have been harsh in my wording, I wanted to express something similar to Schwern so I will try an be clearer. I believe Occam's Razor applies here -- complex pointer arithmetic is less clear and harder to maintain than other options available. When I said "silly" I meant more obtuse and complex than it needed to be.
|
3

There are a few problems with this question, most of which are addressed by Schwern's answer. I'll address some more things though, including the point in the original question about not counting spaces:

  1. To reiterate, C arrays are 0-indexed.

  2. You probably want an unbounded loop, so that you can add more elements to your array without changing the code (and the number 1000 convolutes the solution). At this point, the maximum value of x becomes sizeof(myArray) / sizeof(myArray[0]), the number of elements. You would also let the compiler decide what size to make the array by dropping the 1000 from myArray's definition: char *myArray[] = {"Oh! ", "Hello ", "world."};

  3. The top level loop counts the string length of the full string, but you only want non-space characters. There are many ways to do this, but the most straightforward way is to just count the non-space characters in a nested loop.

Given these things, the following code obtains the desired output:

#include<stdio.h>
#include<string.h>

int main() {
  char *myArray[] = {"Oh! ", "Hello ", "world."};
  int count = 0;
  int arrayLength = sizeof(myArray) / sizeof(myArray[0]);

  for (int x = 0; x < arrayLength; x++) {
    int stringLength = strlen(myArray[x]);

    for (int y = 0; y < stringLength; y++) {
      char currentCharacter = myArray[x][y];

      if (currentCharacter != ' ') {
        count++;
      }
    }
  }

  printf("%d\n", count);
}

Compile it:

gcc test.c -o test

then run it:

./test

and it should output:

14

Given the arrayLength calculation, we can now add a word to myArray and see that the output changes with expectation:

char *myArray[] = {"Oh! ", "Hello ", "world.", "  test     "};

Because there are only 4 non-space characters (test), this should output:

18

Comments

0

A barebones version, for a mildly low-level illustration:

#include <stdio.h>
#include <stdlib.h>

int main() {

char * stringArray[200] = {"O  n e ", " Two  ", "Thre e  ", "Four    ", " F i ve    !"};
int i, j, chars; 
i = j = chars = 0;

while(stringArray[i] != '\0'){
    char temp = stringArray[i][j];
    switch(temp){
        case ' ':
            j++;
            break;
        case '\0':
            i++; 
            j=0;
            break;
        default:
            j++;
            chars++;
            break;           
    }    
}

printf("%d\n", chars);
//o/p == 20

return 0;

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.