C ++: печатать только один символ - PullRequest
1 голос
/ 02 июня 2010

Когда я читаю один char* из std::cin и хочу записать его в std::cout, он печатает, пока не найдет \0 в памяти. Итак, что же было:

char c;
cin >> c;
char* pChar = &c;
pChar++;
*pChar = '\0';
println(&c); // My own method: void println(char * str) { cout << str << endl; }

Но я не думаю, что это безопасное действие.

Есть ли более безопасный способ сделать это?

Ответы [ 6 ]

3 голосов
/ 02 июня 2010

Просто:

char c;
cin >> c;
cout << c;
2 голосов
/ 02 июня 2010

Уже есть несколько ответов о том, как делать то, что вы хотите сделать, но я хотел бы объяснить, что на самом деле под этими pchar++ в вашем коде и почему это зло.

C-style литье дает гибкость, но позволяет вам выстрелить себе в ногу.Вы выделили char c в стеке (это означает, что у вас зарезервировано точное количество памяти, и оно равно sizeof(char), что составляет ровно 1 байт).

Затем вы берете адрес памяти вашей переменной (это нормально), поэтому у вас есть переменная char и указатель на память, где эта char расположен.Но ваш следующий шаг полностью злой, , потому что вы (при выполнении *(pchar + 1) = 0) фактически портите стек.

Как я уже говорил ранее, компилятор зарезервировал ровно один байт для вашего символапамяти, но то, что вы делаете, означает явный переход к следующему байту в этой памяти (который может даже принадлежать стеку другой программы) и переписывание его с вашими собственными значениями.

Это поведение также может быть описано на следующем примере:

Думаю, что вам нужно изменить содержимое какого-то конкретного файла(a.file) на вашем жестком диске.Как вы думаете, можно ли переписать содержимое файлов, которые последовательно следуют a.file, например, увеличить размер этого a.file?

2 голосов
/ 02 июня 2010

Правильно, если вы хотите напечатать символ, вы должны напечатать этот символ:

char ch;
if(std::cin >>ch) 
  std::cout << ch;
else
  // handle input error

И если по какой-то причине вам нужна новая строка за каждым персонажем, сделайте именно это:

std::cout << char << '\n';

Примечание: вы также увидите std::endl, используемый для вывода новой строки, но std::endl делает две вещи: он выводит '\n', а очищает буфер вывода . Хотя последний не является проблемой при выводе на консоль (он все же быстрее, чем человек сможет его прочитать), я видел, что приложения замедляются (при выводе файла) из-за использования std::endl вместо '\n'. Так что лучше с самого начала научиться обращать внимание на то, нужны ли эти буферы очищены или нет.


Обратите внимание, что, где вы делаете

pChar++;
*pChar = '\0';

вы вызываете страшное неопределенное поведение : с помощью pChar++ вы увеличиваете указатель, чтобы указывать за вашей переменной (что нормально), а с помощью *pChar = ... вы записываете в любую память быть за вашей переменной.
На практике это может привести к повреждению вашего стека и, как мы надеемся, к аварийному завершению работы приложения в следующий момент. Однако теоретически это вызывает неопределенное поведение, которое в соответствии со стандартом C ++ может делать что угодно (включая часто упоминаемую возможность того, что он может отформатировать ваш диск).
Не записывайте в память, которой вы не владеете.
сложно для новичков правильно понять указатели, поэтому просто избегайте их везде, где можете. Вы можете многое сделать с C ++, даже не манипулируя указателями вручную.

1 голос
/ 02 июня 2010
char c;
cin >> c;
char pChar[2] = {0};
pChar[0] = c;;
println(pChar); 

Или, если вы хотите больше походить на C ++, перегрузите функции:

void println( const char * s ) {
   cout << s << endl;
}

void println( char  c ) {
   cout << c << endl;
}

Или даже шаблон:

template <typename T >
void println( T t ) {
   cout << t << endl;
}
0 голосов
/ 02 июня 2010
char c;
std::cin >> c;
if (std::cin) {
    std::cout << c << std::flush;
}

Этот код печатает "только один символ". std::cout << c << std::endl печатает два: c и '\n'.

Вы также можете использовать функцию println, если хотите:

char str[2] = {'\0', '\0'};
std::cin >> str[0];
if (std::cin) {
    println(str);
}

Обратите внимание, что if (std::cin) заставляет компилятор вызывать operator void*() const член класса std::ios, который расширяется std::istream, чтобы оценить std::cin как логическое значение.

0 голосов
/ 02 июня 2010

Печать введенного вами символа:

char c = 0;
std::cin >> c;
std::cout << c;

Получить символ в строке и получить первый символ:

char c = 0;
std::cin >> c;
std::string str;
str += c;

std::cout << str.at(0) << std::endl;

EDIT

Или, может быть, вы просили об этом? :

std::string str;
std::cin >> str;

std::cout << str;

Я не совсем уверен, в чем действительно проблема.

...