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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

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

Q&A

解決済

8回答

3134閲覧

C言語について

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

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

0グッド

0クリップ

投稿2016/08/02 03:25

C言語についての質問があります。

C言語で scanf()がありますが、
char buf[32];
scanf("%s", buf);

通常は上記のように作ると思います。
これを、入力と同時に変数の配列を確保していく方法を教えてください。
C++ の std::cin >> でも同じことは可能でしょうか??

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

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

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

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

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

guest

回答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
raccy

総合スコア21733

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

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

strike1217

2016/08/02 23:33

すばらしいい!! ありがとうございます!
strike1217

2016/08/02 23:36

scanf("%s", buf); これはオーバーフローを起こす危険性があるから、ヤバいのですか?? それとも、もっとヤバい危険があるのでしょうか??
raccy

2016/08/03 09:18

バッファオーバーフローは最も危険なバグの一つです。単に動作しない、停止するという問題が発生するだけではなく、重大なセキュリティホールの原因になり得ます。たかがサンプルぐらいという意識は大変危険です。日頃から、起こさないように気をつけないと、本当に起こしてはいけないプログラムで同じ事をしてしまいます。
strike1217

2016/08/09 03:59

ありがとうございます
guest

0

入力した文字列に合わせた配列を作りたい、ということでしょうか?
C言語では「領域を確保する→そこにデータを格納する」ということしかできません。
mallocを使うにせよ、配列を使うにせよ、予め用意しないといけないということです。

投稿2016/08/02 03:31

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

strike1217

2016/08/02 03:32

あああ~~。 そうなんですか! わかりました。 ありがとうございます。
退会済みユーザー

退会済みユーザー

2016/08/02 03:35

十分な大きさの配列を用意して一度そこに入れ、後からピッタリの大きさの領域をmallocで作成して放り込む、ということならできます。
guest

0

入力と同時に変数の配列を確保していく方法を教えてください。

POSIX準拠のシステムに限定するならば、scanf書式指定子%smオプションを指定("%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

yohhoy

総合スコア6189

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

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

strike1217

2016/08/02 23:33

やってみます!! ありがとうございます
guest

0

Cでは、標準入力(ファイルでも同様ですが)から文字列を取得する際はあらかじめ領域を確保する必要があります。動的に確保する方法はありますが、その場合、一定の文字数を取り出しては連結していくというような処理になります。

C++ の std::cin >> でも同じことは可能でしょうか??

可能です。C++なら、入力時に必要に応じて領域を確保することができます。
ただし、その際、char配列ではなくSTLのstringクラスを使います。

C++

1std::string buf; 2std::cin >> buf;

投稿2016/08/02 04:16

catsforepaw

総合スコア5938

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

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

strike1217

2016/08/02 23:34

やはり、stringはすごいですね! ありがとうございます
guest

0

getchar()等を使って自力で1文字入力して格納して…を繰り返す処理を作ればできますがそういう事では無いんでしょうか…?ちょっと質問が分かりにくいです…

投稿2016/08/02 03:35

HiroshiWatanabe

総合スコア2160

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

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

strike1217

2016/08/02 03:36

1文字ずつだと結構大変ですよね。 malloc()を使えば、できるかな・・と思っていたのですが。
guest

0

scanfの %s に関してはこういう記事もあります。
http://www.kijineko.co.jp/tech/superstitions/buffer-overrun-of-scanf.html

投稿2019/07/07 12:56

myoon

総合スコア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

HogeAnimalLover

総合スコア4830

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

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

strike1217

2016/08/02 23:35

ありがとうございます。
guest

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
A.Ichi

総合スコア4070

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

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

strike1217

2016/08/02 23:35

ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問