views:

184

answers:

5

Hi all

I'm trying to write a program that counts all the characters in a string. I originally had it, but then realized I can't count spaces. I can't see why this does not work.

for(m=0; z[m] != 0; m++) {
    if(z[m] != ' ') {
        charcount ++;
    }
}

Any assistance appreciated.

Edit* Does it make a difference if the input(strings) are being scanned in like this? And yes, everything is initialized. I've tried printing what z[m] evaluates too and it isn't the actual value of the string at "m", I think this is the problem.

for(j=0; j<7; j++){
    printf("Enter a string:\n");
    scanf("%s", z);
        for(m=0; z[m] != 0; m++){
                if(z[m] != ' '){
                charcount ++;
                }
        }
+3  A: 

You need to initialize charcount. Other than that, it should work, provided that z is a zero-terminated array of characters and m is an int or similar. I would probably write just z[m] rather than z[m] != 0 (since !0 = true and 0 = false), but both work. There are more efficient ways of doing it (although these days I bet a compiler will handle converting this into a pointer-based loop for you).

Here's a complete, correct example with minimal edits:

const char * z = "testing one two three";
int m;
int charcount;

charcount = 0;
for(m=0; z[m]; m++) {
    if(z[m] != ' ') {
        charcount ++;
    }
}

If you're using a String class of some kind rather than an old-fashioned C null-terminated array, you'll want to look at that class for how to loop through it.

All of the above also assumes you're dealing with ASCII strings. If you're dealing with UTF-encoded strings, you have to handle multi-byte characters.


Re your edit: It makes a big difference: scanf will stop on the first blank (I'd forgotten that). It might make an even bigger difference than that, though, if you're not declaring z correctly. (I'd also recommend using a field width when using scanf for reading strings [or avoiding scanf entirely]; otherwise, you have no control over the number of chars it will try to store, and so in theory, no buffer will ever be big enough to avoid an overflow. More here: http://www.crasseux.com/books/ctutorial/String-overflows-with-scanf.html)

T.J. Crowder
`'\0'` and `0` are the same. One is not more correct than the other. One can, perhaps, be more *stylish* than the other.
pmg
@pmg: No, they're not. `'\0'` is a `char`, `0` is an `int`. It's a distinction that makes no difference in this code, though.
T.J. Crowder
Try this: `sizeof '\0'`. I don't think I've ever seen a literal char in `C` (except inside `char[]`).
pmg
@pmg: I'm talking about type information, not the size of the storage used.
T.J. Crowder
This post is **NOT** tagged `C++`. I'd have made the distinction if it were.
pmg
and `'\0'` is an int!
pmg
@pmg: C has types, too. `char` and `int` are not the same, even in C, even though any compiler I've ever seen will happily and silently promote and demote as necessary (esp. with constants). That doesn't mean they're the same thing, and it *certainly* doesn't mean programmers who are clearly a bit new to this and that should get in the habit of treating them as though they were the same. I'm bowing out of this conversation, feel free to have the last word.
T.J. Crowder
@pmg: *"and `'\0'` is an int!"* I'd be interested to see a reference on that. But again, leaving the floor to you. Best.
T.J. Crowder
re: `scanf`, you _can_ in fact control the maximum field width for `%s`.
Hasturkun
@T.J.: C99, § 6.4.4.4 2: "An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in 'x'." § 6.4.4.4 10: "An integer character constant has type int."
outis
@Hasturkun: I'd edited it.
T.J. Crowder
Compare C++03 § 2.13.2 1: "A[n ordinary] character literal is one or more characters enclosed in single quotes, as in ’x’[...]. An ordinary character literal that contains a single c-char has type char, with value equal to the numerical value of the encoding of the c-char in the execution character set. An ordinary character literal that contains more than one c-char is a multicharacter literal. A multicharacter literal has type int and implementation-defined value."
outis
@outis: Thanks!
T.J. Crowder
@pmg: Changed, and thanks for the info. I would write `!z[m]` anyway... :-)
T.J. Crowder
Sorry everyone ... I had to get away from the computer for a while. Thank you `outis` for fishing the reference for me and I'm glad this issue is settled.
pmg
@All: I'd delete my erroneous comments above, but then the other comments would look odd, so let's just assume people are smart enough to read all the way through...
T.J. Crowder
A: 
int i=-1;
while(z[++i]);

then i is your string length;

if you want only characters (no spaces included) then

int j=0,i=-1;
while(z[++i])
{
if (z[i] != ' ')
j++;
}

then j should be your characters count;

HPT
...which is basically what his code is doing, just using `while` rather than `for`.
T.J. Crowder
A: 

you can use strlen() http://www.cplusplus.com/reference/clibrary/cstring/strlen/

I'd suggest using a while loop, and to use more meaningful variablenames

m = textIndex z = text

something liek this

while (text[textIndex] != 0x00) { textIndex++; }

Anonymous
How does `strlen` help him know how many **non-space** chars are in the string?
T.J. Crowder
strlen() would be useful for me, except it seems to print out the length of each word individually rather than on one line.
James
@TJ: `scanf` skips spaces itself already, and stops scanning when it reaches the next space.
R..
@James: As "R" says, that's because `scanf` stops on the first bit of whitespace, as I mentioned in my edited answer when you edited your question to say you were using `scanf`.
T.J. Crowder
@R: As of Anonymous' answer and my comment, we didn't know `scanf` was involved.
T.J. Crowder
A: 

Instead of using scanf, try fgets like so:

char input[256];
fgets(input, sizeof(input), stdin);

fgets will read an entire line from a file. As such, passing stdin as the file handle will make it read from standard input, which in most cases will be bound to the console. One thing to watch out for, though, is that the string you get from fgets might include the newline character. Rather than explicitly checking your strings for inequality with the space character (' '), I suggest using the isspace function from ctype.h, which will check for various forms of whitespace (including a regular space and newline).

Here is a complete, runnable example:

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

int count_nonspace(const char* str)
{
 int count = 0;
 while(*str)
 {
  if(!isspace(*str++))
   count++;
 }
 return count;
}

int main()
{
 char input[256];
 fgets(input, sizeof(input), stdin);
 printf("%d\n", count_nonspace(input));
}
Martin Törnwall
A: 

Yes, there is a difference on input-scan with scanf:

    scanf("%s", z);
...
                if(z[m] != ' '){

scanf("%s"...) always breaks at space-character, therefore your if ever is true. Better you use fgets to read from stdin,

#define MAXINPUT 80
char line[MAXINPUT];
for(j=0; j<7; j++) {
  printf("Enter a string:\n");
  if( fgets( line, 80, stdin ) )
  {
    char *c=line;
    if( strchr(line,'\n') ) *strchr(line,'\n')=0;
    while( *c )
    {
      if( *c!=' ' )
        ++charcount;
      ++c;
    }
  }
}

Or if you want WHITE -spaces then take

#include <ctype.h>
...
if( !isspace(*c) )