質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

7回答

4348閲覧

C++の回数を指定しない文字列の入力処理について

ten9

総合スコア15

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/02/28 12:13

編集2018/03/01 03:08

タイトルの付け方が下手でごめんなさい。
C++の入力処理で、回数を指定しない文字列の入力処理はどのように実装すればよいのでしょうか。例えば、

cpp

1int n; 2char str[10]; 3cin >> n; 4for(int i=0; i<n; i++){ 5 cin >> str[i]; 6}

のような処理では、範囲を決めてfor文を扱うことができますが、nの値が決まっていない文字列の入力の場合はどういったものを作ればよいのでしょう。nの入力がなく、改行が入るまでの範囲を文字列として扱いたいときなどです。stringを使えば解決できるのでしょうが、char配列として文字列を扱う場合についての回答をいただきたいです。
よろしくお願いします。

※追記
文章が足らず、申し訳ありません。
経緯としては、一行で与えられる文字列の中で特定の文字を数字に置き換えて出力する、という問題を解くにあたって、char配列を使おうと思いました。しかし、この問題では上記の例でいうnが与えられません。一行を読み取って一文字ずつ配列に格納する方法を知らなかったため、このような質問をさせていただきました。
そのため、「char配列縛り」というわけではなく、stringなどを用いて、結果として配列として処理ができるような方法を教えていただきたいのです。宜しくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2018/03/01 02:52

目的・用途も書いた方がいいかもしれません。charとstringは別物でchar[]がほしいからなのか、それとも課題なのか...
guest

回答7

0

ベストアンサー

単純にstringで受けた後にchar配列を生成してはいかがでしょうか?
以下ではchar配列strは通常の(\0終端)文字列として扱うようにしています。

C++

1#include <iostream> 2#include <cstring> 3int main() { 4 char *str(nullptr); 5 std::string s; 6 if( std::getline(std::cin,s)){ 7 str = new char[s.length()+1]; 8 strcpy( str, s.c_str()); 9 } 10 11 if( str){ 12 // 何らかの処理 13 std::cout << str << std::endl; 14 delete [] str; 15 } 16 return 0; 17}

追記を受けて。std::replaceを使えば楽ですね。
なお、以下コードでは複数個の文字を置換していますが、英字→数字など、置換元先の文字がかぶらない前提です。
複数個の任意の文字について置換する場合は、処理を見直す(一度置換した文字は再置換しないようにする)必要があります。

C++

1#include <iostream> 2#include <algorithm> 3int main() { 4 std::string s = "abcabcde"; 5 std::string rep("ac"), num("12"); // a->1, c->2 6 for( int i = 0; i < rep.length(); i++){ 7 std::replace(s.begin(), s.end(), rep[i], num[i]); 8 } 9 std::cout << s << std::endl; // 1b21b2de 10 return 0; 11}

上の回答だとアレなのでepistemeさんの回答をパクリ参考に平易に書いてみました。

C++

1#include <iostream> 2#include <map> 3int main() { 4 std::string src("abcabcde"); 5 std::string repFrom("ac"), repTo("12"); // a->1, c->2 6 7 // 置換マップ作成 8 std::map<char,char> mRep; 9 for( int i = 0; i < repFrom.length(); i++){ 10 mRep[repFrom[i]] = repTo[i]; 11 } 12 13 // 置換 14 std::string dst; 15 for( int i = 0; i < src.length(); i++){ 16 char c(src[i]); 17 auto it = mRep.find(c); 18 if (it != mRep.end() ) { 19 c = it->second; 20 } 21 dst += c; 22 } 23 std::cout << dst << std::endl; // 1b21b2de 24 return 0; 25}

投稿2018/03/01 02:40

編集2018/03/01 08:35
can110

総合スコア38256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2018/03/01 02:46

うん、そぉなのよね。"stringを使わずに"の意図が知りたいわ。 stringからはconst char*が得られないと思って(る|た)のかしら...
can110

2018/03/01 02:51

>stringからはconst char*が得られないと思って(る じゃないかなあと思います。 あるいはstringからconstじゃないchar配列へのコピー方法か
episteme

2018/03/01 03:09

あー、そーかも。 *copy(s.begin(), s.end(), str) = '\0'; // C関数使ったら負け(ナンチテー
ten9

2018/03/01 03:53

得られないと思って(た...。stringから配列を作れば良かったのですね。 ※質問文、少々追記したのでよろしければ参照してください。
can110

2018/03/01 04:03

追記しました。char配列でもできますが、stringだけの方が楽できます。
ten9

2018/03/01 04:06

わざわざありがとうございます。replaceという機能を知りませんでした...。stringのほうがコードもきれいになるし、stringはstrongだなぁ(ごめんなさい)。
episteme

2018/03/01 04:29

※ ただしこのやり方では a→c c→a 変換を試みると"しょんぼり"する。
can110

2018/03/01 04:55 編集

あ~!問題ちゃんと読んでなかったです。 回答は英字→数字など、元先の文字がかぶらない前提ですが 任意の文字に置換だと、複数回置換の罠にひっかかりますね。
episteme

2018/03/01 05:05

質問からはそこまで読み取れないので"但し書き"付きでOKやと思うです。
can110

2018/03/01 05:11

そうですね~ ただ良い気づきになりました。指摘コメントありがとうございます。
ten9

2018/03/01 05:12

質問は文字→数字だったので書いていただいたコードで大丈夫です!ありがとうございます。 ※お聞きしたいのですが、複数回置換の罠というのは上記の例の場合だとnum("ca")の場合とかでしょうか?その場合、どう問題が生じるのでしょう。文字は1文字ずつ処理されているので、置換で異常をきたすことはないと思っていたのですが...。
can110

2018/03/01 05:16

元文字列「abc」を「a」は「c」に、「c」は「a」にするケースでは 期待する結果は「cba」ですが、回答コードでは「aba」になってしまいます。 置換された文字は再置換してはいけない(=各文字は1度だけ置換する)です。
ten9

2018/03/01 05:19

なるほど!再置換の可能性があったのか。回答、感謝です。
episteme

2018/03/01 07:45

僕の回答は再置換問題が起きませんです(エッヘン
guest

0

char配列として文字列を扱う場合

配列は固定長でないとならないので、ちょっとしたテクニックがいります。
Cならmalloc()とrealloc(),free()を組み合わせるんでしょうが・・・

下記サイトにクラスを使ったサンプルが有ります。
Resizing arrays
文字を格納するのに、最初に確保した領域に入りきれない場合、領域を倍々にしていく方法です。
このクラスに、char operatorでも追加すれば文字列として扱えると思います。

投稿2018/02/28 12:59

編集2018/02/28 13:03
cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ten9

2018/03/01 04:01

ポインタ(new)を使うのか!盲点でした。参考にさせていただきます。
guest

0

改行が入るまで
stringを使えば解決できるのでしょうが

std::getline

あっさり解決しますから、使いましょう。

など

https://github.com/hoxnox/cro2sql/blob/master/src/freader.cpp#L88

こんな感じに頑張れば。こう考えるとget_unillみたいな処理はRustのほうが簡単にかけるなぁ。

投稿2018/02/28 12:27

編集2018/02/28 12:29
yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ten9

2018/03/01 04:03

おとなしく使わせていただきます。 (Rust、興味あるんですがC++をもっと身に着けてからかなぁ...。)
guest

0

一行で与えられる文字列の中で特定の文字を数字に置き換えて出力する

まかしとき。

C++

1 2#include <iostream> 3#include <iterator> 4#include <map> 5#include <string> 6#include <algorithm> 7 8int main() { 9 using namespace std; 10 // 変換表 11 map<char,char> conv = { 12 { 'a', '0' }, // a を 0 に 13 { 'b', '1' }, // b を 1 に 14 { 'c', '2' }, // 以下同文 15 { 'd', '3' }, 16 { 'e', '4' }, 17 }; 18 string input = "apple cherry banana"; 19 string result; 20 transform(input.begin(), input.end(), 21 back_inserter(result), 22 [&](char ch) -> char { 23 auto i = conv.find(ch); 24 return ( i == conv.end() ) ? ch : i->second; 25 }); 26 cout << input << " -> " << result << endl; 27} 28 29/* 実行結果 30apple cherry banana -> 0ppl4 2h4rry 10n0n0 31*/

stringなどを用いて、結果として配列として処理ができるような...

stringはcharの配列とみなしていいよね? それとも char[] じゃなきゃ却下?

[追記] 変換対象はイッコだけ? だったらもっと簡単

C++

1#include <iostream> 2#include <string> 3#include <algorithm> 4 5int main() { 6 using namespace std; 7 string str = "apple cherry banana"; 8 replace(str.begin(), str.end(), 'a', '?'); 9 cout << str << endl; 10} 11 12/* 実行結果 13?pple cherry b?n?n? 14*/

投稿2018/03/01 03:38

編集2018/03/01 03:49
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ten9

2018/03/01 03:50

stringで全然平気です。(逆にchar[]のほうが使いづらいと知りました。) 例まで書いていただき、ありがたいです。(transformとかラムダ式とか勉強せねば...)
guest

0

一行で与えられる文字列の中で特定の文字を数字に置き換えて出力する

これなら std::stringで十分です。

私なら、特定の文字を 例えば 'a' だとして、その特定文字'a' をstd::string::findで検索する。
で、その位置をstd::string::replace ( std::string::substrだったか? ) で 書き換える。

これでやると思う。


[追記1]

確か、ネットでもリファレンスっていうの?関数辞典みたいなのがあったはず。

C言語版:
C言語関数辞典

C++版:
cpprefjp

cppreference.com

あと一個あった気がしますが...

こういうのでそれぞれのクラスが持つメンバを確認したり、引数,戻り値を確認したりといろいろ調べてみてください。

投稿2018/03/01 03:17

編集2018/03/01 03:55
BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ten9

2018/03/01 03:43

そんな機能があったとは!string便利だなぁ(遠い目)。 回答ありがとうございます。stringでチャレンジしてみます。
ten9

2018/03/01 03:59

わざわざ追記まで!ありがたいです。 cpprefjpは結構使わせていただいています。Cへの知識が薄いから、関数辞典も有効活用せねば...。
guest

0

シバリがキツい...vectorだけでも使わせてくださいぃ

C++

1#include <iostream> 2#include <iterator> 3#include <vector> 4#include <algorithm> 5 6int main() { 7 using namespace std; 8 vector<char> buffer; 9 const char delim = '\n'; 10 cout << "enter CR-terminated string :" << flush; 11 12 istreambuf_iterator<char> first(cin), last; 13 find_if(first, last, 14 [&](char ch) { 15 bool eol = ch == '\n'; 16 buffer.push_back(eol ? '\0':ch); 17 return eol; 18 }); 19 const char* result = buffer.data(); 20 21 cout << '[' << result << ']' << endl; 22} 23 24/* 実行結果 25enter CR-terminated string :hogehoge payopayo 26[hogehoge payopayo] 27*/

投稿2018/03/01 01:18

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

先の回答者がおられるので別の視点から。

一応、ソフトウェア上は「無限」とか「可変」といった概念を扱うことができるとされています。が、当然ですけれど、ハードウェア上の制約がある以上、無限のメモリを確保することは現実には不可能です。

どこまでいっても、イレギュラーな運用をするユーザがおられますので、あまり「無限」のものを使うというのは望ましくはありません。バグとかセキュリティホールになります。ルールを取り決めたうえで、有限の資源の中で処理をするということも必要になります。

投稿2018/02/28 13:23

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ten9

2018/03/01 03:56

可変といってもメモリ不足とかありますしね...。 制限をかけた運用をせねばいけない。参考になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問