C言語についての質問があります。
C言語で scanf()がありますが、
char buf[32];
scanf("%s", buf);
通常は上記のように作ると思います。
これを、入力と同時に変数の配列を確保していく方法を教えてください。
C++ の std::cin >> でも同じことは可能でしょうか??
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答8件
0
ベストアンサー
scanf("%s", buf);
うわぁ、コレはヤバイ。マジでヤバイ。どれぐらいヤバイかって言うとgets
ぐらいヤバイ。
上のヤバイ話はさておき、いくつか方法を示します。
まず、1番目はバッファに収まるサイズを取ってきて、続きがあるようなら、領域を増やして、またその分を取得するです。
C
1#include <ctype.h> 2#include <stdio.h> 3#include <stdlib.h> 4 5// 読み取るときのサイズ 6#define BUF_SIZE 32 7#define BUF_SCAN_S "%32s" 8 9int main(void) 10{ 11 char *buf; // バッファ、常に先頭 12 char *p; // バッファで文字を入れていく部分をしめすポインタ 13 size_t buf_size = BUF_SIZE + 1; // '\0'分余計に必要 14 buf = malloc(buf_size); // メモリを動的確保 15 if (buf == NULL) { 16 fprintf(stderr, "%s\n", u8"メモリ確保に失敗しました。"); 17 return 1; 18 } 19 p = buf; 20 buf[0] = '\0'; // 空文字にしておく 21 while (scanf(BUF_SCAN_S, p) == 1) { 22 // 次の文字をチェック 23 int c = getchar(); 24 // 入力が閉じられているのでscanfで見るのは終わり 25 if (c == EOF) { 26 break; 27 } 28 // 次の文字も戻しておく 29 ungetc(c, stdin); 30 // 次が空白文字なのでscanfで見るのは終わり 31 if (isspace(c)) { 32 break; 33 } 34 // 次の取得に向けて準備する 35 buf_size += BUF_SIZE; // BUF_SIZE分増やす 36 buf = realloc(buf, buf_size); // メモリ確保量を増加 37 if (buf == NULL) { 38 fprintf(stderr, "%s\n", u8"メモリ確保に失敗しました。"); 39 return 1; 40 } 41 // 次に文字を入れているところにポインタを設定しておく 42 p = buf + (buf_size - BUF_SIZE - 1); 43 } 44 printf("%s\n", buf); 45 free(buf); // メモリ解放 46 return 0; 47}
結構面倒です。32個ずつ見ていくのに、バッファは常に32の倍数+1というのも気持ち悪いです。
2番目は、getchar()
で一個ずつ取ってくるです。HiroshiWatanabeさんが言っている方法ですね。
C
1#include <ctype.h> 2#include <stdio.h> 3#include <stdlib.h> 4 5// 読み取るときのサイズ 6#define BUF_SIZE 32 7 8int main(void) 9{ 10 char *buf; // バッファ、常に先頭 11 char *p; // バッファで文字を入れていく部分をしめすポインタ 12 size_t buf_size = BUF_SIZE; 13 buf = malloc(buf_size); // メモリを動的確保 14 if (buf == NULL) { 15 fprintf(stderr, "%s\n", u8"メモリ確保に失敗しました。"); 16 return 1; 17 } 18 p = buf; 19 int c; 20 while ((c = getchar()) != EOF) { 21 // 空白文字なら、バッファに戻して終わり 22 if (isspace(c)) { 23 ungetc(c, stdin); 24 break; 25 } 26 // 文字を入れてpを進める 27 *p = c; 28 p++; 29 // p が終端まで来ている場合は領域を増やす 30 if (p == buf + buf_size - 1) { 31 buf_size += BUF_SIZE; // BUF_SIZE分増やす 32 buf = realloc(buf, buf_size); // メモリ確保量を増加 33 if (buf == NULL) { 34 fprintf(stderr, "%s\n", 35 u8"メモリ確保に失敗しました。"); 36 return 1; 37 } 38 // 新しい領域で再設定 39 p = buf + (buf_size - BUF_SIZE - 1); 40 } 41 } 42 *p = '\0'; // '\0' 終端を忘れずに 43 printf("%s\n", buf); 44 free(buf); // メモリ解放 45 return 0; 46}
最初のよりはましかな。バッファの確保方法を工夫すれば(固定で増やすのでは無く倍ずつにするなど)、Cなら一番理想的だと私は思っています。
3番目はC11標準じゃ無い%ms
を使う方法です。yohhoyさんの言っている方法ですね。
C
1/** 2 * GNU版、gcc + glibc 環境でないと動かないと思う。 3 * `gcc -std=gnu11`でコンパイルすること。 4 */ 5#include <stdio.h> 6#include <stdlib.h> 7 8int main(void) 9{ 10 char *buf; // バッファ 11 int r = scanf("%ms", &buf); 12 if (r != 1 || buf == NULL) { 13 fprintf(stderr, "%s\n", u8"何か失敗した。"); 14 return 1; 15 } 16 printf("%s\n", buf); 17 free(buf); 18 return 0; 19}
yohhoyさんによるとPOSIXなシステムでればとありましたが、実質glibc 2.7以上でしか実装されていないっぽいです。Mac OS Xでは動きませんでした。(glibc使っているLinuxならいける、Mac OS Xでglibcにリンカ貼ればいけるかも知れない)
最後は、C++です。std::stringは素晴らしいです。catsforepawさんが言っている方法ですね。
C++
1#include <cstdio> 2#include <iostream> 3#include <string> 4 5int main() 6{ 7 char *buf; 8 std::string str; 9 std::cin >> str; 10 buf = const_cast<char *>(str.c_str()); 11 printf("%s\n", buf); 12 return 0; 13}
他とあわせるために、char *buf;
にしていますが、一番すっきりします。
getchar()
の戻り値をchar
に入れてた…泣きたい。
投稿2016/08/02 11:21
編集2016/08/02 22:27総合スコア21751
0
入力した文字列に合わせた配列を作りたい、ということでしょうか?
C言語では「領域を確保する→そこにデータを格納する」ということしかできません。
mallocを使うにせよ、配列を使うにせよ、予め用意しないといけないということです。
投稿2016/08/02 03:31

退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2016/08/02 03:35

0
入力と同時に変数の配列を確保していく方法を教えてください。
POSIX準拠のシステムに限定するならば、scanf書式指定子%s
にm
オプションを指定("%ms"
)できます。事前に必要なバッファサイズがわからなくても、scanf関数内部でmalloc確保されたメモリ領域に文字列を取得できます。利用後はfreeをお忘れなく。
C
1#include <stdio.h> 2#include <stdlib.h> 3 4int main() 5{ 6 char *s = NULL; 7 if (scanf("%ms", &s) == 1) { 8 printf("\"%s\"\n", s); 9 free(s); 10 } 11}
投稿2016/08/02 10:32
総合スコア6191
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
Cでは、標準入力(ファイルでも同様ですが)から文字列を取得する際はあらかじめ領域を確保する必要があります。動的に確保する方法はありますが、その場合、一定の文字数を取り出しては連結していくというような処理になります。
C++ の std::cin >> でも同じことは可能でしょうか??
可能です。C++なら、入力時に必要に応じて領域を確保することができます。
ただし、その際、char配列ではなくSTLのstringクラスを使います。
C++
1std::string buf; 2std::cin >> buf;
投稿2016/08/02 04:16
総合スコア5944
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
getchar()等を使って自力で1文字入力して格納して…を繰り返す処理を作ればできますがそういう事では無いんでしょうか…?ちょっと質問が分かりにくいです…
投稿2016/08/02 03:35
総合スコア2160
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
scanfの %s に関してはこういう記事もあります。
http://www.kijineko.co.jp/tech/superstitions/buffer-overrun-of-scanf.html
投稿2019/07/07 12:56
総合スコア100
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
mallocを使うにしても固定長配列にしても、先にサイズがわからないと実現できないですね。Cならばサイズを決めることが必要です。例えばscanf("%d", &size);とかで先に長さの入力を促すとか、以下のように対話的な処理をするかが必要ですね。
C
1printf("一度に読み込めるのは○文字までです。これより多くの文字を入力する場合は分割してください。\n"); 2for(int flag = 1; flag; scanf("%d", &flag) ){ 3 scanf("%s", buf); 4//一時変数bufの中身をリスト管理するなどを行う 5 printf("続きがある場合は0以外の数字を、終了する場合は0を入力してください。\n"); 6} 7
投稿2016/08/02 03:59
総合スコア4853
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
char buf[32];は確かに配列で、32バイトの文字の領域を確保します。
scanfは%sにて取得した文字列を先頭アドレスbufから並べて値を配置します。buf[0]から順に並べます。
ですのでscanf("%s", &buf[0]);とも書けます。
入力文字は32を越えてはなりません。
c++(g++)の場合std:cinは文字を扱うので文字列とする場合 std::getline(std::cin, buf);になるのかな
投稿2016/08/02 03:55
編集2016/08/02 03:56総合スコア4070
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/08/02 23:33
2016/08/02 23:36
2016/08/03 09:18
2016/08/04 02:17
2016/08/09 03:59