0

So, I made a program that lets the user type in his full name, showing its initials. (using a char array, so the names will be delimited by a space).

This is my code:

#include <iostream>
#include <cstring>
using namespace std;

int main()
{
   char name[100];
   cout << "Name: "; cin >> name;
   cout << name[0];
   for (int i = 1; i<=strlen(name); i++)
      if (name[i] == 32)
         cout << name[i+1];
   return 0;
}

It will find the space between the names and the things that will be shown are the first element from the array and the next element after the space.

For example, if I type in: John Doe, the output will be: J D.

My problem is, it only shows J. Why?

Mateaș Mario
  • 77
  • 1
  • 6

2 Answers2

2

Because std::cin >> name will only read characters until whitespace is encountered.

Try using std::getline to read the entire line (read until line break).

std::string s;
std::getline(std::cin, s);
std::cout << s[0] << " " << s[s.find(' ') + 1] << std::endl;

Note: above has no bounds check, e.g., if no space is found.

Felix Glas
  • 15,065
  • 7
  • 53
  • 82
  • So, using getline(cin, name) would do it? – Mateaș Mario Jan 25 '18 at 21:11
  • @MateașMario Yes, except that `std::getline` expects to read into a `std::string` variable. Which makes sense. Use `std::string`. – Felix Glas Jan 25 '18 at 21:13
  • @Snps Though there really should be bounds checking, in this case it'll work out (in the sense that the behavior is at least well defined). [`std::string::find`](http://en.cppreference.com/w/cpp/string/basic_string/find) returns [`std::string::npos`](http://en.cppreference.com/w/cpp/string/basic_string/npos) if it fails to find something. Due to how `unsigned` integer types work, `npos + 1` is well defined and produces `0`. So in this case, if there are no spaces, it would print the first letter twice (assuming the string isn't empty). – François Andrieux Jan 25 '18 at 21:50
  • When searching searching for a single character, prefer `s.find(' ')`. – François Andrieux Jan 25 '18 at 21:51
1

std::cin >> name reads a single word from the input stream. It never read the second word.

You could use std::getline()[1] to read a whole line of input, or you could read single words in a loop using std::cin >> word.

Either way, I would strongly recommend using std::string instead of C strings. strlen(name) will have to count the string length on each iterator of the loop.

You're also potentially reading beyond the end of the string with i <= strlen(name) and reading name[i+1].

Something like this should work (untested):

#include <iostream>
#include <string>

int main() {
   std::string name;
   std::getline(std::cin, name);

   for (std::size_t i = 0; i < name.size(); i++) {
      if (i == 0 || name[i - 1] == ' ') {
        std::cout << name[i];
      }
   }
}
Maarten
  • 106
  • 4
  • Wasn't it `< name.size()` or `<= name.size()-1`? – Mateaș Mario Jan 25 '18 at 21:17
  • It would be if you were reading just `name[i]`. But since you're also reading `name[i+1]` you need to stop your loop one iteration earlier. – Maarten Jan 25 '18 at 21:18
  • Changed the answer to read `name[i - 1]` (if `i != 0`) and `name[i]`, so then the loop should indeed continue until `i < name.size()` – Maarten Jan 25 '18 at 21:24