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

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

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

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

3回答

522閲覧

C言語 文字型配列について

hal335

総合スコア2

C

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

1クリップ

投稿2021/05/27 13:05

前提・実現したいこと

最近配列や文字列を勉強したばかりの初心者です。

1画面のサイズが80*24として、4画面分の文字列を2次元配列で以下のように宣言しています。

char title[24*4][80] = {"・・・(省略)"}

エンターを押すたびにこの文字列を1画面分ずつprintf()関数で表示するプログラムを作っています。
ただし、printf()関数の呼び出しは4回に抑えたいです。

発生している問題・エラーメッセージ

1画面分の文字列を格納する変数(str)を用意して、strcat()関数でその中に文字列(title)を順次複写していき、1画面分の複写が終わったらprintf()関数を実行してから変数を初期化する、というプログラムを作ろうと思いました。

そこで以下のプログラムを作成しましたが、メモリ破壊が起きていることが分かりました。

C

1char str[] = ""; 2 3// タイトル画面処理 4void DrawTitle(void) 5{ 6 /* 画面描画処理 */ 7 for (int y = 0; y < 24 * 4; y++) 8 { 9 //文字列の連結 10 strcat(&str[0], &title[y][0]); 11 12 if ((y + 1) % 24 == 0) 13 { 14 //1画面ずつ表示する 15 printf("%s", str); 16 17 //文字列の初期化 18 strcpy(&str[0], ""); 19 20 /* ウェイト */ 21 rewind(stdin); 22 _getch(); 23 24 /* 画面クリア */ 25 system("cls"); 26 } 27 } 28}

試したこと

メモリ破壊について調べたところ、配列の要素数を超えて要素を代入したり、存在しない添え字を指定したりすることで発生するという風に理解しました。
なので、まずこの部分で「要素数を省略すると要素数は初期値の数と同じになる」ということを忘れていたので、1画面分の文字列+ヌル文字用の1文字を要素数として宣言するように修正しました。

//修正前 char str[] = ""; //修正後 char str[24 * 80 + 1];

また、文字列の初期化のやり方が間違っているのではないかと考えて、以下のように修正しました。

//修正前 strcpy(&str[0], ""); //修正後 strcpy(&str[0], "\n");

修正後のソースコード

C

1//要素数を省略すると初期値の数と同じになる 2//1画面分の文字列を格納する変数。ヌル文字用に+1。 3char str[24 * 80 + 1]; 4 5// タイトル画面処理 6void DrawTitle(void) 7{ 8 /* 画面描画処理 */ 9 for (int y = 0; y < 24 * 4; y++) 10 { 11 //文字列の連結 12 strcat(&str[0], &title[y][0]); 13 14 if((y + 1) % 24 == 0) 15 { 16 //1画面ずつ表示する 17 printf("%s", str); 18 19 //文字列の初期化 20 strcpy(&str[0], "\n"); 21 22 /* ウェイト */ 23 rewind(stdin); 24 _getch(); 25 26 /* 画面クリア */ 27 system("cls"); 28 } 29 } 30}

質問したいこと

・自己流で修正してみたんですが、これでメモリ破壊は治っていますでしょうか?
・printf()関数は4回以内という条件で、自分が考えた方法よりもっと良い方法がありましたら教えていただきたいです。

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

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

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

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

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

neconekocat

2021/05/27 14:11

DrawTitleに限って言えば、バッファオーバーランが起きるかどうかはtitle次第です。 試しにDrawTitleの先頭にmemset(title, 0x30, sizeof(title));と書いてみてください。余裕で死にます。
hal335

2021/05/27 14:18

書いてみました。死にました。
guest

回答3

0

ベストアンサー

バッファオーバーランを防ぐ方法としては一旦別の変数に確保する等があります。
Cの文字列について調べながら、なぜ防ぐことができるか(元のコードはなぜ防げないか)を考えていけば、他の方が指摘している内容も理解できるようになると思います。

C

1// タイトル画面処理 2void DrawTitle(void) 3{ 4 char str[24 * 80 + 1]; 5 char tmp[80 + 1]; 6 //終端文字を設定 7 tmp[80] = 0x00; 8 9 /* 画面描画処理 */ 10 for (int y = 0; y < 24 * 4; y++) 11 { 12 //1行分の文字列を抽出 13 strncpy(tmp, title[y], 80); 14 15 //文字列の連結 16 strcat(str, tmp); 17 18 if((y + 1) % 24 == 0) 19 { 20 //1画面ずつ表示する 21 printf("%s", str); 22 23 //文字列の初期化 24 str[0] = 0x00; 25 26 /* ウェイト */ 27 rewind(stdin); 28 _getch(); 29 30 /* 画面クリア */ 31 system("cls"); 32 } 33 } 34}

投稿2021/05/27 14:55

neconekocat

総合スコア443

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

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

0

strcatについての理解が間違っているのでしょう。

strcat(a,b)は、
aのアドレスから後方に'\0'を探して、見つかった'\0'のアドレス以降に、bのアドレスから'\0'が出てくるまでをコピーする」
という機能です。

つまり、初期化していないエリアにstrcatすると範囲外アクセスが生じる可能性があります。

あと、

char title[24*4][80] = {"・・・(省略)"}

のデータがそもそもおかしいのでは?
「1行の文字は79文字以下でその後には'\0'が入っている」ということなら、これでいいのですが。

行単位に'\0'が入っていないのであれば、行単位では扱えません。

別のアプローチとしては、文字列として扱わず、つまり、文字列用関数を使わず、全部サイズ指定で処理するという方法もあります。

投稿2021/05/27 14:08

編集2021/05/27 14:36
otn

総合スコア85901

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

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

0

char str[] = "";

この配列のサイズはいくらだと思いますか?
1しかありません。
ここに、文字列をコピーするだけで、アクセス違反となります

投稿2021/05/27 13:59

y_waiwai

総合スコア88042

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問