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

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

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

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

Q&A

解決済

5回答

606閲覧

C言語でメモリ解放について

Alyn

総合スコア50

C

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

0グッド

1クリップ

投稿2018/07/17 12:44

編集2018/07/19 23:54

Cで領域を超えた文字列を処理したい。

領域を超えた場合に勝手に文字列を出力させなようにして、while文の繰り返し処理をさせる方法を教えてください。
free関数では溢れたものまでは処理できなくて困ってます。

該当のソースコード

C言語

1#include<stdio.h> 2#include<stdlib.h> 3 4int OverFlow(char *str) 5{ 6 if (*str == NULL) 7 { 8 return -1; 9 } 10 return 1; 11} 12int main(void) 13{ 14 char *mojiretu; 15 int jdg = 0; 16 17 while (jdg != 1) 18 { 19 mojiretu = (char *)malloc(5); 20 if (mojiretu == NULL) 21 { 22 printf("メモリ確保失敗。\n"); 23 break; 24 } 25 26 printf("文字列を入力:"); 27 scanf_s("%s", mojiretu, 5); 28 jdg = OverFlow(mojiretu); 29 if (jdg == -1) 30 { 31 printf("領域を超えています。\n"); 32 free(mojiretu); 33 } 34 } 35 if (jdg == 1) 36 { 37 printf("入力された文字列は%sです。\n", mojiretu); 38 } 39 40 return 0; 41 42}

追記

文字列を入力:abcdefgh
領域を超えています。
文字列を入力:123
入力された文字列は123です。

となるようなプログラムを作りたいです。

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

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

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

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

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

cateye

2018/07/17 22:38

mojiretuは何処で解放してますか?
Alyn

2018/07/19 13:49

何処とは何でしょうか?
cateye

2018/07/19 14:42

main()の終了で、プログラムが終了するので開放はされるのですが、returnの前にfree()で開放するほうがいいと思いますが?
Alyn

2018/07/19 14:43

入力をやり直しさせたいのですが、どうしたらいいですか?
asm

2018/07/19 16:24 編集

期待する動作・実際の動作を提示してほしいです。 abcdefと6文字入力すると"領域を超えています\nf" と出力されるのがイヤって事でしょうか?
guest

回答5

0

溢れたらそれでおしまい、です。
freeでもなにを使ったところで回復できません
溢れる前に、それを検出して止めるようにしないとダメです

投稿2018/07/17 13:03

y_waiwai

総合スコア87774

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

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

Alyn

2018/07/17 14:02

どうしたらよいでしょうか?
y_waiwai

2018/07/17 23:26

自分のコードの中で、溢れないようにしっかりデバッグする、しかないですね
asm

2018/07/20 04:21

scanfじゃなくてscanf_sなんだよなぁ
guest

0

何が問題なのか良くわかりませんが、

printf("文字列を入力:");

mojiretsu[0] = '\0';//これを入れないといけないのでは?
scanf_s("%s", mojiretu, 5);
jdg = OverFlow(mojiretu);
if (jdg == -1)

としないと、
OverFlow(mojiretu);
で、-1 が帰ってこない可能性が多々あるように思いますが。

ついでに、
if (jdg == -1)
{
printf("領域を超えています。\n");
free(mojiretu);
}
の部分で読み込みきれなかった文字列を読み捨てる必要が無いでしょうか?

投稿2018/07/18 05:41

PingHermit

総合スコア478

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

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

Alyn

2018/07/19 13:54

mojiretuが4文字を超えてしまうと中身が\0となっていましたので、-1は返ってきますよ
guest

0

ベストアンサー

y_waiwaiさんの回答からの流れでの回答を欲ししてるようなので便乗して。

C言語の場合、メモリを溢れさせないように常に気をつけないといけません。
mallocで5バイトだけ確保していても、余裕で領域オーバーして数百バイトでも書き込めます。
その代わり他のプロセスが使っているかもしれない領域を上書きしているのですから、何が起きてもおかしくはありません。
そのためにも予防は必要です。
例えば厳格な業務アプリなんかでは、今回の例のようにscanfで文字入力するようなことはまずありません。
なのでscanfを使うのはちょっとしたお試しプログラムを書く場合などと思っててください。
という前提で予防の話をしますと、最初に5バイトmallocしていますが、それとは別に大きな領域を用意して、scanfでの入力はそちらに取り込むようにします。
大きな領域とは今回の例では自分で入力するであろう最大の文字数です。10でも20でも100でもよいです。
そしてその入力されたものの文字数を数えて5バイトを超えていたら警告するような作りになります。

c

1mojiretu = (char *)malloc(5); 2work = (char *)malloc(100); 3while(1){ 4 printf("文字列を入力:"); 5 scanf_s("%s", work, 100); 6 if(strlen(work) < 5){ 7 break; 8 } 9 printf("領域を超えます。\n"); 10} 11strcpy(mojiretu, work);

厳密には文字列の終端にはNULL文字が必要なので、mallocで5バイト確保していても4文字しか格納できません。

投稿2018/07/18 00:06

編集2018/07/19 23:53
ttyp03

総合スコア16998

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

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

macof

2018/07/18 02:07

細かいことで申し訳ありませんが、 一般的なメモリ保護を行うOS上であればプロセスは独立した論理空間を持ちますから、 未確保の領域にアクセスしただけで他所のプロセスのメモリを上書きしてしまう可能性を危惧する必要はないかと思われます。
ttyp03

2018/07/18 02:09

「プロセス」って書いちゃうとダメですね。 指摘ありがとうございます。
asm

2018/07/18 02:27

Win9x系のカーネル領域は共有されてると噂には聞いた事がありますね
y_waiwai

2018/07/18 05:43

まー、Cが走る環境はWindowsとも限らないし、ましてやインテルCPU上とも限りませんし
Alyn

2018/07/19 14:00

これは領域を超えてしまうと終了ですか? 入力をやり直すことはできないのですか?
y_waiwai

2018/07/19 14:08

終了です。そうなるとなにが起こっても文句言えません まあ、malloc(5)のときにホンマはもうちょっとたくさん確保しているってこともあるので、大丈夫なときもあるでしょうけど、それは保証できない世界になります
ttyp03

2018/07/19 23:30

shibu-mさん >これは領域を超えてしまうと終了ですか? これってどれを指しているのですか? 私が提示したコードでしょうか。 であるなら単なるサンプルなので、もう一度入力させたいのであれば、mallocから下の処理をループで回せばよいかと。
Alyn

2018/07/19 23:50

もう一度入力をやり直そうとすると溢れた文字列が勝手に入力されて出力されてしまうので、自分で再入力させたいです。
ttyp03

2018/07/19 23:54

コードを修正してみたのでご確認ください。
guest

0

C言語の標準入力の仕様です。

対応策は

  • scanf/scanf_sを使用したらgetcで改行もしくはEOFを検知するまで読み取る
  • %*[^\n]を用いて読み飛ばしを行う
  • fflush(stdin);でバッファクリアできる環境もある(規格上定義された動作ではない)
  • fgetsを用いて1行入力した後にsscanf/sscanf_sを用いる

投稿2018/07/20 00:29

編集2018/07/20 00:31
asm

総合スコア15147

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

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

0

OverFlow()内 if(*str == NULL)は、文字の比較になっていませんか?

繰り返し入力させるなら、確保→入力→解放の繰り返し while()の条件見直し。
システム(OS)の空きメモリ開放は時間がかかるのでfree()推奨d^^。
あと・・・メモリが確保できなというのは考えづらい。
ちなみにうちの機械(linux:mem16GB)では、8GBぐらいなら余裕で確保できます。

「追記」
繰り返し入力&メモリ確保失敗と入力長異常に対応(題意にそぐわないなら無視希望)

c

1usr~/test/c % cat ct.c 2#include<stdio.h> 3#include<stdlib.h> 4#include<string.h> 5 6#define Forever for(;;) 7 8int main(void) 9{ 10 char *mojiretu; 11 char buf[100]; 12 13 Forever{ 14 mojiretu = (char *)malloc(5); 15 if (mojiretu == NULL) 16 { 17 puts("メモリ確保失敗。"); 18 break; 19 } 20 21 printf("文字列を入力:"); 22 fgets(buf,sizeof buf - 1, stdin); 23 size_t len= strlen(buf); 24 if( len > 5 ){ 25 puts("領域を超えています。"); 26 free(mojiretu); 27 continue; // break→continue 28 } 29 buf[len-1]= '\0'; // 改行を削除 30 strcpy(mojiretu,buf); 31 printf("入力された文字列は%sです。\n", mojiretu); 32 free(mojiretu); 33 } 34 35 return 0; 36} 37 38usr~/test/c % ./a.out 39文字列を入力:1234567 40領域を超えています。 41文字列を入力:abc 42入力された文字列はabcです。 43文字列を入力:1234 44入力された文字列は1234です。 45文字列を入力:12345 46領域を超えています。 47文字列を入力:0 48入力された文字列は0です。 49文字列を入力:^C 50usr~/test/c %

一部修正しました、ただ、これだとメモリ確保に失敗しないと終了しません、

投稿2018/07/19 15:08

編集2018/07/20 00:37
cateye

総合スコア6851

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

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

Alyn

2018/07/19 15:26

すみません、初心者なので全然わからなくて… どんなコードですか?
cateye

2018/07/19 15:32

まず、if(*str == NULL)をif(str == NULL)にして試してみて下さい。
cateye

2018/07/19 15:55

環境がわからないのでなんとも言えませんが、デバッガないですか?・・・ 変数のプリントを仕込むこともできますよd^^
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問