
あれから後一歩と言うところにきました
たぶんmallocのバグだと思いますがチャットのシステムを作ろうとしているのですが
読み込み時にエラーになります
ソースの注目部分を見てほしいのですが、
注目部分はbuf+1 にすると 文字列が1文字ずつ消えていくバグになり
bufにすると 3行目を書き込んだ時点で3行目がの頭の部分の文字列がおかしくなり4行目を書き込もうとするとエラーになります
ちゃんと動作するにはどのように書けば良いですか?
---ソース---
#include <stdio.h>
void main(void){
FILE *fp;
char *tm[1000];
char buf[400];
int i=1,sei;
fp= fopen("now.txt","w+");
fprintf(fp,"もも");
fclose(fp);
//何で最初に書き込んでるんだ?
//という突っ込みがあるでしょうが本当に作りたいプログラムは最初にファイルに書き込まないといけないためです。
fp= fopen("now.txt","r");
while( fgets( buf, 400, fp ) != NULL ){
tm[0]=(char*)malloc(strlen(buf)+1);
strcpy(tm[0], buf);
}
fclose(fp);
fp =fopen("moto.txt","r");
while( fgets( buf, 400, fp ) != NULL ){
tm[i] = (char*)malloc(strlen(buf+1));
strcpy(tm[i], buf+1); //ここを注目
if(i<999){
i++;
}
}
fclose(fp);
if(i<=1000){
sei=i;
}
else{
sei=1000;
}
fp =fopen("moto.txt","w");
for(i=0;i<sei;i++){
if(i==0){
fprintf(fp,"%s\n",tm[0]);
}
else{
fprintf(fp,"%s",tm[i]);
}
}
}
---now.txt---
もも
---moto.txt---
オレンジ
みかん
No.5ベストアンサー
- 回答日時:
>+1を入れると\0がはいるんじゃないんですか?
strlen()は「引数で渡されたアドレスから」文字列終端までの長さを返します。
'\0'が入る領域を用意するのであれば、「strlen()の返した値」に+1する必要があります。
ですので、"123456789"と9文字入っているアドレスの"2"が入っているところから数えたら8文字しかありませんよね?
掲示されたコードは"2"から数え始めてね。と指定しているのです。
# そして、"2"からコピーしてね。としてコピーしています。
>fp= fopen("now.txt","r");
>while( fgets( buf, 400, fp ) != NULL ){
>tm[0]=(char*)malloc(strlen(buf)+1);
>strcpy(tm[0], buf);
>}
では、正しく「文字数+1」となっているのに、問題の箇所では「先頭2文字目からの文字数」となっているのはなぜですか?
>つまりstrcpy(tm[i], buf+3);
>にすれば何とかなるのですね
そりゃエラーにはならないかも知れませんが、それが想定している動作なんですか?
掲示されたファイルの例(Shift-JIS想定)だと……
1回目で(3行目がヘンになっているかも知れない。半角カナになっている為)
---moto.txt---
激塔W
(空行)
ゥん
2回目の実行で
---moto.txt---
ジ
(空行)
(空行)
(空行)
になりますかね。
# 3行目が空行かゴミが出るかは状況次第のギャンブル。
>想定外と申されましても試行錯誤して書き換えているので想定そのものができません
では期待動作はなんなんでしょうか?
この回答への補足
>>>+1を入れると\0がはいるんじゃないんですか?
strlen()は「引数で渡されたアドレスから」文字列終端までの長さを返します。
'\0'が入る領域を用意するのであれば、「strlen()の返した値」に+1する必要があります。
あ、そういえばそうですね
勘違いしてました
+1入れろと書いてあったので間違えたようです
>>ですので、"123456789"と9文字入っているアドレスの"2"が入っているところから数えたら8文字しかありませんよね?
掲示されたコードは"2"から数え始めてね。と指定しているのです。
# そして、"2"からコピーしてね。としてコピーしています。
ポインターの位置換えですね
だから1行目が消えたのですね
>fp= fopen("now.txt","r");
>while( fgets( buf, 400, fp ) != NULL ){
>tm[0]=(char*)malloc(strlen(buf)+1);
>strcpy(tm[0], buf);
>}
では、正しく「文字数+1」となっているのに、問題の箇所では「先頭2文字目からの文字数」となっているのはなぜですか?
見落としてかいたのか試行錯誤しているうちに偶然に書き換えてしまったからです
指摘していただきありがとうございます。
>つまりstrcpy(tm[i], buf+3);
>にすれば何とかなるのですね
<<そりゃエラーにはならないかも知れませんが、それが想定している動作なんですか?
掲示されたファイルの例(Shift-JIS想定)だと……
1回目で(3行目がヘンになっているかも知れない。半角カナになっている為)
---moto.txt---
激塔W
(空行)
ゥん
2回目の実行で
---moto.txt---
ジ
(空行)
(空行)
(空行)
になりますかね。
# 3行目が空行かゴミが出るかは状況次第のギャンブル。
想定の意味が自分が思ったようにこうしたいと言う理想の処理と言う意味であれば
想定外ですよ
申し訳ありませんね
想定の意味がプログラムを書き換えた後で必ずこうなる事を知っている事が想定と言う意味だと勘違いしていました
>想定外と申されましても試行錯誤して書き換えているので想定そのものができません
>>では期待動作はなんなんでしょうか?
期待している動作
1回目の動作で
もも
みかん
オレンジ
をmoto.txtの内容にする
2回目の動作で追加したい文字がぶどうなら
ぶどう
もも
みかん
オレンジ
をmoto.txtの内容にする
3回目の動作で追加したい文字がいちごなら
いちご
ぶどう
もも
みかん
オレンジ
をmoto.txtの内容にする
期待している動作はこんな感じです
って私が書いたプログラムをわざわざ修正して2回できるようにしたのですね
お手数おかけして申し訳ありません
このままコメントがなければベストアンサーにさせえていただきますね
No.4
- 回答日時:
>再三指摘されているfgets()での改行コードに
失礼しました。
再三指摘されていたのは別人でした。
たぶんお友達だと思いますけど。
この回答への補足
nanaka2222の事でしたら私自身ですよ
間違えてログアウトしたらパスワードを覚えていなくて戻れなくなりましてnanaka2223jを新たに作りました
ちなみに私に友達はいません
よく見たらNO2~5さんまでWr5さんでしたね
いつもお世話になってありがとうございます
また変な事を聞いていたらすみませんね
今までのおかげでだいぶチャットが完成まじかになりましたよ
機能もいろいろ増えましたしね。
最もミニゲームも加える予定なのでチャットができたら完成って訳ではないんですけどね
今までは一人用のチャットを作れるようにしていたのですが
複数人いた時用のプログラムに以降予定です
ここまでアドバイスしていただき本当にありがとうございました
No.3
- 回答日時:
>ちゃんと動作するにはどのように書けば良いですか?
どういう動作が期待している動作なのか?
が不明です。
とりあえず、問題にしている箇所でバッファオーバーランを発生させないようにするのであれば、
tm[i] = (char*)malloc(strlen(buf+1));
strcpy(tm[i], buf+1);
は
tm[i] = (char*)malloc(strlen(buf)); // buf文字分しかないけど次のコピーで1文字カットするから'\0'の分はある。
strcpy(tm[i], buf+1);
とすべきでしょう。
まあ、これで読み込んだ行の先頭1文字を削除できるか?は、ファイル次第ですけど。
Shift-JISなテキストファイルで1文字目に日本語とか書かれていたら…ヘンになるかも知れませんし、
ASCIIで記述されたテキストファイルならたぶん正しく1文字目が削除されるでしょう。
# 現状のmoto.txtだとたぶん壊れます。
再三指摘されているfgets()での改行コードに関しては…まぁ、問題ないのでしょう。
私的には気持ち悪い処理内容ですが……。
# 部下や教えている生徒がこういうコード書いてきたら、なぜそうなるのかキチンと説明を求めるレベル。
「1行目の次に空行を挿入して、それ以降の行は空行を挿入しない処理です。」以外の回答があるのかは謎。
この回答への補足
期待している動作
1回目の動作で
もも
みかん
オレンジ
をmoto.txtの内容にする
2回目の動作で追加したい文字がぶどうなら
ぶどう
もも
みかん
オレンジ
をmoto.txtの内容にする
3回目の動作で追加したい文字がいちごなら
いちご
ぶどう
もも
みかん
オレンジ
をmoto.txtの内容にする
期待している動作はこんな感じです
<<まあ、これで読み込んだ行の先頭1文字を削除できるか?は、ファイル次第ですけど。
Shift-JISなテキストファイルで1文字目に日本語とか書かれていたら…ヘンになるかも知れませんし、
ASCIIで記述されたテキストファイルならたぶん正しく1文字目が削除されるでしょう。
# 現状のmoto.txtだとたぶん壊れます。
逆です1文字目が消えちゃうからバグなのです
一文字も消えずにそのまま表示したいのです
<<再三指摘されているfgets()での改行コードに関しては…まぁ、問題ないのでしょう。
それは修正しましたよ
<<私的には気持ち悪い処理内容ですが……。
私から見れば順番に処理画家かれてるので見やすいですが、他の方が同様のプログラムを作る場合なんて全くないのでどうして気持ち悪いのかわかりません。ごめんなさい。
ただ他の人の書いたソースは見ずらいと言うことでしたら私も同様にみづらいなと思うこともあるのでお互いさまなのではないでしょうか?
<<# 部下や教えている生徒がこういうコード書いてきたら、なぜそうなるのかキチンと説明を求めるレベルなぜそうなるのかと言われましても順番に処理を書いていってバグなどがおきたり新しい処理を追加していったらいつの間にか自然とそうなったとしか、後はそのため試行錯誤を繰り返したらそうなったとしかいえません
<<「1行目の次に空行を挿入して、それ以降の行は空行を挿入しない処理です。」以外の回答があるのかは謎
そういう風に答えれば良いんですね
でしたら最初の一行目は一度別のファイルに文字列をすべて書き込んで文字列をつなげた一つの文字列にしました
その理由は漢字、ひらがな、#等の文字をstrcatで連結させようとするとめちゃくちゃバグるからです
そのっため別のファイルに書き込んだ文章を再び呼び出してtm[0]に格納しました
その次にmoto.txtにかかれた文字列を順次tm[i]に格納して文字列をつなげて表示したかったのですがバグが発生しました
3行目で最初の文字が消えるだけでなく、4行目を書き込もうとしたらエラーになる
そのため試行錯誤してバグを取り除こうとした結果、最初の一文字つつきえるとはいえチャットのように何行も書き込める方法を発見ちょっと喜びました
その後バグがなくなるよう試行錯誤したのですが発見できずこちらで相談させていただきました
このような回答でよろしいでしょうか?
No.2
- 回答日時:
malloc()のバグではなく、「使い方」の問題でしょう。
今時malloc()にバグが潜在するようなライブラリなんてないでしょうし。
>tm[i] = (char*)malloc(strlen(buf+1));
の意図ってなんでしょう?
なぜ「bufのアドレスに+1」する必要があるんですか?
文字列終端の'\0'の分が確保されませんから、次の
>strcpy(tm[i], buf+1); //ここを注目
で、『予定通り』バッファオーバーランを実行します。
# tm[i] = (char*)malloc(strlen(buf)+1);
# だったら、「bufに入っている文字列をコピーするのに必要なサイズ」が確保されますけど…
# 掲示されたコードでは「bufに入っている文字列を2文字少なくコピーできるサイズ」しかありません。
バッファオーバーランで想定外の箇所を書き換えているのですから…
>文字列が1文字ずつ消えていく
>3行目を書き込んだ時点で3行目がの頭の部分の文字列がおかしくなり4行目を書き込もうとするとエラー
という動作になっても想定内のハズです。
この回答への補足
>>tm[i] = (char*)malloc(strlen(buf+1));
の意図ってなんでしょう?
なぜ「bufのアドレスに+1」する必要があるんですか?
文字列終端の'\0'の分が確保されませんから、次の
>strcpy(tm[i], buf+1); //ここを注目
で、『予定通り』バッファオーバーランを実行します。
+1を入れると\0がはいるんじゃないんですか?
# 掲示されたコードでは「bufに入っている文字列を2文字少なくコピーできるサイズ」しかありません。
つまりstrcpy(tm[i], buf+3);
にすれば何とかなるのですね
<バッファオーバーランで想定外の箇所を書き換えているのですから…
<という動作になっても想定内のハズです。
想定外と申されましても試行錯誤して書き換えているので想定そのものができません
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
InternetReadFileで大きいファ...
-
バイナリファイルをテキストフ...
-
VS2010 MFC CStdioFileについて
-
巨大なテキストファイル(可変...
-
【VB.Net】バイト型配列に読み...
-
C言語初心者の質問失礼します。
-
Wordファイルの結合
-
ファイル形式またはファイル拡...
-
SGファイルって何ですか?
-
フルパスから最後のディレクト...
-
バッファとは何ですか
-
シェルコマンドの 2>&1 とはど...
-
FTPでputすると空ファイルが出...
-
営業秘密の漏洩について
-
実行ファイルと実行モジュール...
-
絶対パスの絶対て英語で何でし...
-
OLE又はDDEを使うVISUAL BESIC...
-
コンポーネント`MSCOMM32.cox'...
-
windows.hがincludeされない
-
VisualStudioのプロジェクトリ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
テキストファイルの行数を取得...
-
ファイル内のデータを1行削除...
-
バイナリファイルをテキストフ...
-
fgetsで2行目から文字化け
-
ファイルサイズ指定し、ファイ...
-
c言語 2つのファイルを行ご...
-
0x00をファイル出力
-
C言語での採番について
-
VBSで指定行に挿入
-
テキストファイルの先頭への文...
-
fopen(ファイルパス)
-
C言語での改行コードの扱いにつ...
-
fopenで開いたファイルのサイズ...
-
winsock recvでの文字化け
-
EOF判定されない
-
fscanf関数のscanf集合を使う時...
-
巨大なテキストファイル(可変...
-
VS2010 MFC CStdioFileについて
-
(UWSC)このような場合、解決策...
-
改行までの一文字ずつのファイ...
おすすめ情報