0

When I get string input by using char arrays and I cycle through them with a for loop, my code always has random character outputs that should not be there.

I have tried debugging my code, by checking the output at various stages, but I can't find the reason for what is happening.

    int k, s, counter = 0;
    char word[21];

    std::cin>>k;
    std::cin.getline(word,21);
    for (int i = 0; word[i] != ' '; i++)
    {
        s = 3*(i + 1) + k;
        std::cout<<s;
        for (int k = 0; k < s; k++)
        {
            word[i]--;
            if (word[i] < 'A')
               word[i] = 'Z';
        }
    std::cout<<word[i];
    }

When I type in 3 to get the value of k, I already get the output "URORIFCFWOQNJCEBFVSPMJNKD" when I should not get any output.

Hugetanks
  • 21
  • 3
  • 1
    Welcome to Stack Overflow! Please take the [tour] and read [ask]. Concerning your issue, please extract a [mcve]. Without that, your question is considered off-topic unfortunately, even though the problem itself may well be on-topic. – Ulrich Eckhardt May 20 '19 at 17:22
  • 1
    Does the input string have a space? If not `for (int i = 0; word[i] != ' '; i++)` will cause a problem. – Johnny Mopp May 20 '19 at 17:24
  • 2
    1) Seems that it's, at least, relevant to [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction), if it's not duplicate. 2) Why are you using `char` arrays to read strings, instead of `std::string`? – Algirdas Preidžius May 20 '19 at 17:24
  • What is that code supposed to do? There are many odd things going on in it. – Ted Lyngmo May 20 '19 at 17:33
  • @JohnnyMopp since the size of the string the user input varies, I thought I would use the word[i] != ' ' to stop the for loop when it encounters a space in the char array. – Hugetanks May 20 '19 at 19:27
  • @TedLyngmo the code is supposed to be for this question: https://dmoj.ca/problem/ccc12j4 – Hugetanks May 20 '19 at 19:28

2 Answers2

1

The problem is that the buffer is not flushed before using getline.
Because of that when you hit enter after entering a number, that enter (character '\n') is passed to getline(), and at that point getline ends his work by leaving the word empty.

The solution to this is simple: Flush the buffer before getline.

Here is the complete solution:

#include <iostream>

int main() {
    int k, s, counter = 0;
    char word[21];

    std::cin>>k;

    // Clear the buffer
    std::cin.clear();
    while (std::cin.get() != '\n') 
    {
        continue;
    }

    std::cin.getline(word,21);

    std::cout<<"TEST>"<<word<<"<TEST"<<std::endl<<std::flush;

    for (int i = 0; word[i] != ' '; i++)
    {
        s = 3*(i + 1) + k;
        std::cout<<s;
        for (int k = 0; k < s; k++)
        {
            word[i]--;
            if (word[i] < 'A')
               word[i] = 'Z';
        }

        // Use std::flush to forcefully print current output.
        std::cout<<word[i]<<std::flush;
    }
}

Notes:

  • I've used the buffer clearing mechanism described there. You might use another, but the idea is the same
  • If you comment the 4 lines of that buffer clearing part, you'll notice that as soon as you type "3" and hit enter, you see an output like "TEST><TEST" which means that the word inside it, is empty.
  • Consider using std::flush while using cout if you want forcefully print the output before the for cycle ends.
Just Shadow
  • 7,001
  • 2
  • 40
  • 51
  • The flushing works, thanks, but what does the std::flush at the end do? Although you said it forcefully prints the output, I don't see a difference with and without the std::flush – Hugetanks May 20 '19 at 19:33
  • When you try to print something on the screen using methods like cout, it doesn't immidiately get printed as it might be time-consuming. So, it gets buffered and printed only from time to time. For example, if you have a cout in a for loop, you might notice that every time you cout something from that loop, it's not immidiately is printed on screen. You might use std::flush to force all that buffered stuff to be printed. Here is some example: https://stackoverflow.com/a/38112106/5935112 and slightly more details https://stackoverflow.com/q/22026751/5935112 – Just Shadow May 21 '19 at 05:45
0

std::cin >> k; is reading an integer only. It does not read the trailing line break. The documentation of the >> operator says

The extraction stops if one of the following conditions are met:

  • a whitespace character [...] is found. The whitespace character is not extracted.

As Just Shadow pointed out this line break is causing the getline() call to return an empty string.

You can ignore any number of line breaks by calling

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

BTW: Looking at your outer for loop I would be concerned that you might read beyond the end of word if the string doesn't contain any whitespaces. The following solution fixes that as well:

#include <iostream>
#include <limits>

int main() {
    int k, s, counter = 0;
    char word[21];

    std::cin >> k;
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.getline(word, 21);
    for (int i = 0; i < sizeof(word) && word[i] != ' '; i++)
    {
        s = 3 * (i + 1) + k;
        std::cout<<s;
        for (int k = 0; k < s; k++)
        {
            word[i]--;
            if (word[i] < 'A')
               word[i] = 'Z';
        }
        std::cout << word[i];
    }
}
Martin Konrad
  • 847
  • 1
  • 9
  • 18