0

int number is a paramter for the function this code is from. first_digit is a string that has been passed the first value from a ifstream file

else if (number != 0)
    {
        std::string number_string = std::to_string(number);
            while (!file.eof() )
            {
                if (first_digit[0] == number_string)
                {
                    count++;
                }
            file >> first_digit;
            }

What I am trying to do is have count++ iff the first digit from the file matches the char value of parameter int number. AKA I am trying to count the lines for which the first digit matches number. number is passed from a separate function that will send number for(i=1;1<10;i++) so that I will end with a total sum for the number of times the first digit in the file is 1, 2, 3 etc etc

What I am struggling with is the conditional! How can I relate the first index position of string first_digit to int n on the basis of they hold the same char value? e.g. '1' == '1' therefore count++

Angew is no longer proud of SO
  • 156,801
  • 13
  • 318
  • 412
  • Is it possible that you pass a `char number` as parameter to the function that code is from? After all, you want to count lines starting with a given character, not with a given number (what is if the number is greater than 9?) – bennofs Oct 04 '13 at 16:39
  • 3
    Note: [fix your while-loop](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – WhozCraig Oct 04 '13 at 16:42

3 Answers3

0

The numeric values of digit characters are guaranteed to be increasing and consecutive. In other words, I believe you're looking for this:

if (first_digit[0] == '0' + number) {
  //...
}
Angew is no longer proud of SO
  • 156,801
  • 13
  • 318
  • 412
  • Which will work as long as `number <= 9`. If `number` is some large value (e.g. 1000), this will give *interesting* results. – Zac Howland Oct 04 '13 at 17:11
  • @ZacHowland It will just never be true (on 8-bits-to-byte hardware), because the arithmetic is done in `int`s and `first_digit[0]` is a `char`. And I understood from the question that `0 <= number <= 9` is a precondition of the function. – Angew is no longer proud of SO Oct 04 '13 at 17:19
  • I don't see anywhere where he states `number` is checked prior to entering the function (nor inside the function), but if it is, then there is no problem. If it is not, the results will not be desirable (when an `int` is downgraded to a `char` and the `int` was larger than 255 ...) – Zac Howland Oct 04 '13 at 17:32
  • @ZacHowland There are no "downgrades" in my code. `'0'` will be promoted to `int` because the other operand of `+` is an `int`, and then `first_digit[0]` will be promoted to an `int` because the other operand of `==` is an `int`. If the function states `0 <= number <= 9` to be its precondition (as I understand it), then it's the calling code's responsibility to guarantee that, and the function can take it for granted. "If preconditions are not met, the behaviour is undefined." – Angew is no longer proud of SO Oct 04 '13 at 17:37
  • "If preconditions are not met, the behavior is undefined." - which was my whole point. I saw no preconditions set in his question and your answer assumes them without specifying it. – Zac Howland Oct 04 '13 at 17:45
  • @ZacHowland Quoting the question: "number is passed from a separate function that will send number `for(i=1;1<10;i++)`" – Angew is no longer proud of SO Oct 04 '13 at 17:46
  • Ah, my mistake then ... I missed it. – Zac Howland Oct 04 '13 at 17:49
0

What you are attempting to do will only work if number is between 0 and 9. Additionally, if first_digit is a string, then first_digit[0] is a char, which you are then trying to compare to a string (which will not work).

else if (number > 0 && number <= 9) // no sense in checking larger numbers unless you convert the base
{
    std::string number_string = std::to_string(number);
    std::string line;
    while (std::getline(file, line))
    {
        if (line[0] == number_string[0])
        {
            count++;
        }
    }
}

Or, alternatively, you could use std::count_if to do it all for you instead of writing your own loop. It would look something like the following (NOTE: This has not been debugged):

struct line_reader : std::ctype<char>
{
    line_reader() : std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
        rc['\n'] = std::ctype_base::space;
        return &rc[0];
    }
};

// in your conditional

else if (number > 0 && number <= 9) // no sense in checking larger numbers unless you convert the base
{
    std::string number_string = std::to_string(number);
    line_reader myReader;
    file.imbue(std::locale(std::locale(), myReader));
    count = std::count_if(std::istream_iterator<std::string>(file), std::istream_iterator<std::string>(), [&](const string& s)
    {
        return s[0] == number_string[0];
    });
}
Zac Howland
  • 15,149
  • 1
  • 23
  • 37
0

First, there are a couple of problems with your example code. In C++, the EOF-bit is only set after you read something past the end of the file. This means that you will always read one junk line with your code. Instead, you should check if the data you read is actually valid before processing it. (See Why is iostream::eof inside a loop condition considered wrong?)

Also, you should be using std::getline to read the whole line, and not only to the next white space character.

Now on to your actual problem. If you know that number is always less than 10, you can use this trick:

char digit = '0' + number

This works because the numeric value of each digit character is always one greater than the previous. So for example the numeric value of the '1' digit character would be '0' + 1, and so on.

With these changes, the final code is:

// Assert that the number is in the required range. 
assert(number < 10 && number >= 0 && "Expected a single digit!");
std::string line;
while(std::getline(file, line)) {
  if(line[0] == '0' + number) {
    ++count;
  }
}
Community
  • 1
  • 1
bennofs
  • 11,603
  • 1
  • 32
  • 61