fwriteを使うと謎の文字列が追加される。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
helloworld1853
記事: 181
登録日時: 14年前

fwriteを使うと謎の文字列が追加される。

#1

投稿記事 by helloworld1853 » 14年前

http://s1.muryo.etowns.net/~yamada_mama_papa/index.txt に書いてある

文字列をそのまま sample.txtにかくプログラムを作っています。

index.txtには54 45 53 54 45 53 54 0Aと書いてあります。

Visual C++でCtrl+F5を押してビルドし、実行したのですが

sample.txtには

54 45 53 54 45 53 54 0A
文字化けした文字列
C:\Windows\system32\IMM32.DLL
文字化けした文字列
C:\Windows・・・省略
文字化けした文字列
C:\Windows・・・省略
./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ・・・省略
       ・
       ・
       ・
       ・
       ・
       省略


と表示されます。

ちなみにkibou.exeをクリックし直接実行すると

「以下のコンポーネットを参照できませんでした。」

と出てきます。

これとは何か関係があるのでしょうか。

ソースコードは以下に記載します。

ご意見をお聞かせてください。

コード:

#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib,"wininet.lib")

int WRITEFILE(char ptr[])
{
	FILE *fp;
	char *filename = "sample.txt";
	
	/* ファイルのオープン */
	if ((fp = fopen(filename, "b")) == NULL)
	{
		return(-1);
	}

	/* ファイルにデータを書き込む */
	fwrite(ptr, sizeof(int), 4, fp);
	
	/* ファイルのクローズ */
	fclose(fp);
	return(0);
}
int main(void)
{
	HINTERNET hInternet;
	HINTERNET hFile;
	char Buf[10000];
	DWORD ReadSize;
	BOOL bResult;

	/* WININET初期化 */
	hInternet = InternetOpen(
		"WININET Sample Program",
		INTERNET_OPEN_TYPE_PRECONFIG,
		NULL,
		NULL,
		0);

	/* URLのオープン */
	hFile = InternetOpenUrl(
		hInternet,
		"http://s1.muryo.etowns.net/~yamada_mama_papa/index.txt",
		NULL,
		0,
		INTERNET_FLAG_RELOAD,
		0);

	/* オープンしたURLからデータを(10000バイトずつ)読み込む */
	for(;;) 
	{
		ReadSize = 10000;

		bResult = InternetReadFile(
			hFile,
			Buf,
			10000,
			&ReadSize);

		/* 全て読み込んだらループを抜ける */
		if(bResult && (ReadSize == 0))
		{
			break;
		}

		Buf[ReadSize] = '\0';
		printf("%s", Buf);
		WRITEFILE(Buf);
		if(WRITEFILE(Buf)==-1)
		{
			puts("ファイル書き込みに失敗しました。");
			break;
		}
	}

	/* 後処理 */
	InternetCloseHandle(hFile);
	InternetCloseHandle(hInternet);
	return(0);
}

アバター
shiro4ao
記事: 224
登録日時: 15年前
住所: 広島

Re: fwriteを使うと謎の文字列が追加される。

#2

投稿記事 by shiro4ao » 14年前

試してみたところ
私の環境では以下のダイアログが出てきました・・・・
Win7 64bit Professional vc++2010にてコンパイル

---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!

Program: c:\users\eop\desktop\sample\sample\Debug\sample.exe
File: f:\dd\vctools\crt_bld\self_x86\crt\src\_open.c
Line: 98

Expression: ("Invalid file open mode",0)

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)
---------------------------
中止(A) 再試行(R) 無視(I)
---------------------------


どうやら開くモードが不適切(Invalid)だったようです

「バイナリモードでの書き込み」を意味するwbを渡してあげると
書き込み自体はうまくいくようです

コード:

fopen(filename, "wb");
プログラム本体をクリックしたときは
「以下のコンポーネットを参照できませんでした。」
というダイアログはでてきませんでした・・・・
ちょっと、よくわからなくてすみません。



/*追記*/
「文字列をそのまま sample.txtにかくプログラム」にするためには、
書き込みの要素数が少ないように思えます。
fwrite関数に読み込み要素数を伝えてあげる必要がありありそうです

box
記事: 2002
登録日時: 15年前

Re: fwriteを使うと謎の文字列が追加される。

#3

投稿記事 by box » 14年前

helloworld1853 さんが書きました:

コード:

	if ((fp = fopen(filename, "b")) == NULL)
	{
		return(-1);
	}
WRITEFILE()の中で毎回fopenするのは、本当に正しいのでしょうか。
helloworld1853 さんが書きました:

コード:

	fwrite(ptr, sizeof(int), 4, fp);
第2引数がsizeof(int)である理由を教えてください。
helloworld1853 さんが書きました:

コード:

		WRITEFILE(Buf);
		if(WRITEFILE(Buf)==-1)
WRITEFILE()を2回連続で実行している理由を教えてください。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

helloworld1853
記事: 181
登録日時: 14年前

Re: fwriteを使うと謎の文字列が追加される。

#4

投稿記事 by helloworld1853 » 14年前

不具合がたくさん見つかったので大幅に修正します。

ソースコードを見やすくしました。

コード:

 
//webページのソース表示プログラム
//ファイル名:readhtml.c
 
#include<windows.h>
#include<stdio.h>
#include<wininet.h>
 
int main()
{
	HINTERNET hInet, hUrl;
    	char szBuf[128],*IpszSrc;
    	DWORD dwRead,dwTotal=0;
    	HGLOBAL hMem;
	FILE *file;
 
    	//インターネット(winInet)開始
	hInet=InternetOpen(
			"WININET Sample Program",
			INTERNET_OPEN_TYPE_PRECONFIG,
			NULL,
			NULL,
			0);
   
    	//HTTPセッションの開始,指定のURLオープン
	hUrl=InternetOpenUrl(
			hInet,
			"http://s1.muryo.etowns.net/~yamada_mama_papa/index.txt",
			NULL,
			0,
			INTERNET_FLAG_RELOAD,
			0);
 
    	//IpszSrcに1バイトだけ確保する
	hMem=GlobalAlloc(GHND,1);
    	IpszSrc=(char*)GlobalLock(hMem);
    
	//読みだすデータがなくなるまで読みだす
	while(1)
	{
		InternetReadFile(hUrl,szBuf,(DWORD)sizeof(szBuf)-1,&dwRead);
        	szBuf[dwRead]='\0';
 
 
        	//読みだすデータがなくなったらループ終了
        	if(dwRead==0)
        	        break;
        
 
        	//必要バイト数の計算
        	dwTotal+=dwRead;
        
 	
        	//確保領域の大きさ変更
        	hMem=GlobalReAlloc(hMem,dwTotal,GMEM_MOVEABLE);
        	if(hMem==NULL)
		{
        		    perror("再アロケート失敗\n");
        	}
        	IpszSrc=(char*)GlobalLock(hMem);
        	if(IpszSrc==NULL)
		{
        	    perror("メモリ確保に失敗\n");
        	    break;
	        }
        	strcat(IpszSrc,szBuf);
	}
 
	//ソースの表示
	printf("%s\n",IpszSrc);
	file = fopen("sample.txt","wb");
	fwrite(&IpszSrc,sizeof(IpszSrc),1,file);
	fclose(file);
 
	//メモリの解放
	GlobalUnlock(hMem);
	GlobalFree(hMem);
    
	//インターネットハンドルの解放
	InternetCloseHandle(hUrl);
	InternetCloseHandle(hInet);
 
	return 0;
}
先ほど皆様に報告された不具合は修正しました。

しかしそれでうまくいきません。

仕様でしょうか。

box
記事: 2002
登録日時: 15年前

Re: fwriteを使うと謎の文字列が追加される。

#5

投稿記事 by box » 14年前

helloworld1853 さんが書きました: しかしそれでうまくいきません。
どのようにうまくいかないかを書くことは可能でしょうか。
helloworld1853 さんが書きました: 仕様でしょうか。
何の仕様であると思われているのでしょうか。
まあ、プログラムというものは、思った通りには動かないものです。
書いたとおりに動きます。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

helloworld1853
記事: 181
登録日時: 14年前

Re: fwriteを使うと謎の文字列が追加される。

#6

投稿記事 by helloworld1853 » 14年前

不思議なことにソースコードをまったくいじくっていないにもかかわらず

ビルドする度に結果が違うのです。

あるときは 唖C だったりまたあるときは リxH だったりと

ランダムです。 ただ 文字が三文字ぐらいに収まっています。

バイナリエディタで詳しく調べようかと考えています。

初めての体験なのでかなりパニクっています。

検索してもまったく見つかりませんですし・・・

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: fwriteを使うと謎の文字列が追加される。

#7

投稿記事 by beatle » 14年前

毎回文字が変わるのは、恐らく変なメモリ領域を読み込んでファイルに書いているせいです。

helloworld1853さんが本当に問題を解決したいならば、回答者の皆さんの発言、特に今回ならshiro4aoとboxさんの発言をちゃんと読むことです。
読んでいるのかもしれませんが、shiro4aoさんとboxさんの発言に対する反応がまったくありません。外野から見ると無視している印象を受けます。

さて、helloworld1853さんのコードを見ると、ポインタ周りの取り扱いが苦手に見えます。
以下のコード、実行せずに出力結果を予想することはできるでしょうか?

コード:

char s[100], *p;
p = s;
printf("%d\n", sizeof(s));
printf("%d\n", sizeof(p));

box
記事: 2002
登録日時: 15年前

Re: fwriteを使うと謎の文字列が追加される。

#8

投稿記事 by box » 14年前

Windowsとかインターネットとか、余分な要素を取り除いて、
ローカルにあるテキストファイルをfwriteする、というような
単純なプログラムで検証してみてはどうでしょうか。
原因がどこにあるかを切り分けることから始める必要がありそうです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

helloworld1853
記事: 181
登録日時: 14年前

Re: fwriteを使うと謎の文字列が追加される。

#9

投稿記事 by helloworld1853 » 14年前

>shiro4aoさんとboxさんの発言に対する反応がまったくありません。外野から見ると無視している印象を受けます。

すみません。二番目のソースコードでshiro4aoさんとboxさんの

指摘を修正したのですが、

反応を明確に僕が示さず 皆様に悪い印象を与えてしまったのは

僕の不注意です。 以後気をつけます。

さて、テストコードを自分なりに書いてみました。

コード:

#include <stdio.h>

int main(void)
{
	int buf[] = {0x54,0x45,0x53,0x54,0x45,0x53,0x54,0x0A};
	FILE *file;
	file = fopen("test.txt","wb");
	fwrite(buf,sizeof(buf),1,file);
	fclose(file);
	return 0;
}
結果:T E S T E S T

期待していたもの:TESTEST

なぜ結果が微妙に違っていたか謎ですが

一応? 動作しました。

書いてみて気づいたのですが

第二のソースコードポインタが間違っていましたね。

[codeC]
fwrite(&IpszSrc,sizeof((IpszSrc),1,file);
[/code]

[codeC]
fwrite(IpszSrc,sizeof((IpszSrc),1,file);
[/code]

こんな感じでいいでしょうか。

ご指摘がある通り僕はポインタがあまりできていないので

まだ変な所があるかもしれません。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: fwriteを使うと謎の文字列が追加される。

#10

投稿記事 by beatle » 14年前

bufはintの配列であって、それをそのままfwirteしていますから、{0x00000054, 0x00000045, ...}というデータが書き出されています。
8文字の他に、24バイトのナル文字が書き出されているわけですね。

僕の、「無視している」という指摘に対して反応してもらったのはいいのですが、僕のNo.7の質問には答えてもらっていないようです。
helloworld1853さんが陥っている問題を極力シンプルにして出題したつもりですので、是非答えて下さい。

helloworld1853
記事: 181
登録日時: 14年前

Re: fwriteを使うと謎の文字列が追加される。

#11

投稿記事 by helloworld1853 » 14年前

僕は、100だと思いました。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: fwriteを使うと謎の文字列が追加される。

#12

投稿記事 by beatle » 14年前

helloworld1853 さんが書きました:僕は、100だと思いました。
2つのprintfがありますから、2つの数字が出力されるのですけれど、どちらも100と思いましたか?

それでは少し解説しましょう。

コード:

char s[100], *p;
p = s;
printf("%d\n", sizeof(s));
printf("%d\n", sizeof(p));
まずこのソースコードの解説を少し。
1行目で配列sとポインタpを定義しています。
2行目ではポインタpに配列sを代入しています。代入が終わると、pがsを指し示す(ポイントする)状態になります。
何か他の変数を指し示す変数をポインタ変数というわけです。

3行目では、配列sの大きさを出力しています。
4行目では、ポインタpの大きさを出力しています。重要なのは、sizeof(p)は「pが指し示している変数の大きさ」ではなくて、「p自体の大きさ」を取得する方法だということです。

次に、配列とポインタの基礎を。
sはcharの配列、pはchar変数へのポインタですね。
配列というのは、要素がずらっと並んだものですから、sはchar型変数が100個並んだものです。よってsizeof(s)は100です。これは分かりやすい。

ポインタ変数は、それ自身は「アドレス」という値を保持する変数です。
「アドレス」は簡単にいえば、変数の住所のことで、パソコンのメモリのどこに変数があるか示すものです。
プログラムでの「アドレス」は実生活での郵便番号に似ていて、全部整数です。0, 1, 2, ...と、メモリの先頭からアドレスが振られています。
「sの住所は1020です」とか言うんです。

そして、このアドレスは(helloworld1853さんの環境ですと恐らく)4バイトで全部表せますので、ポインタ変数自体は4バイトのサイズしかありません。
配列sは100バイトの大きさですが、配列sの住所は4バイトで表せるわけです。
もし配列sが1万バイトの大きさでも、配列sの住所はやっぱり4バイトで表せます。住所は単なる整数ですから。

ということで、sizeof(p)は(helloworld1853さんの環境ですと恐らく)4になります。

sizeofにポインタ変数を指定して、そのポインタ変数が指し示している変数の大きさを取得しようとするミスは、よく目にしますのでご注意下さい。

helloworld1853
記事: 181
登録日時: 14年前

Re: fwriteを使うと謎の文字列が追加される。

#13

投稿記事 by helloworld1853 » 14年前

なるほど!!

よく分かりました。

改めて僕のソースコードを見ますと・・・

おお・・・  fwriteの箇所が間違っていたのか・・・

fwrite(IpszSrc,dwTotal,1,file);

に修正した結果 動作しました。

皆様のおかげです。

その他小さい疑問があるので 皆様に聞いてみたいと思います。

まず、コンパイルするとfopen,strcatではなくfopen_s,strcat_sをつかえと出てきます。

たぶんオーバーフローを防ぐ?目的だと思いますが、

fopen_s,strcat_sを使えば文字が707000文字あっても無事に動作するのでしょうか。

helloworld1853
記事: 181
登録日時: 14年前

Re: fwriteを使うと謎の文字列が追加される。

#14

投稿記事 by helloworld1853 » 14年前

自己解決しました。

ありがとうございます。

アバター
asd
記事: 319
登録日時: 15年前

Re: fwriteを使うと謎の文字列が追加される。

#15

投稿記事 by asd » 14年前

helloworld1853 さんが書きました:自己解決しました。

ありがとうございます。
できれば、どのように解決したのかを明記してください。
同じ問題で困っている方が出たときのためによろしくお願いします。

---フォーラムルールから引用---
また、解決した時は、「解決しました」とだけ言って去らず、ソースコードや解決した方法を明記して下さい。
同じ事で困っている人の為に過去ログに有用な情報を残すようお願いします。
Advanced Supporting Developer
無理やりこじつけ(ぉ

helloworld1853
記事: 181
登録日時: 14年前

Re: fwriteを使うと謎の文字列が追加される。

#16

投稿記事 by helloworld1853 » 14年前

コード:

#pragma comment(lib, "wininet.lib")
#include<stdio.h>
#include<windows.h>
#include<wininet.h>
#include<string.h>
char DIR(char path[1000])
{	
	HANDLE hFind;
	WIN32_FIND_DATA fd;
	WIN32_FIND_DATA ATONCE;

	char path1[1000];
	DWORD dwAttribute = 0;// ファイルの属性確認
	printf("%s",path);
	wsprintf(path1, TEXT("%s\\*.*"), path);

	hFind = FindFirstFileA(path1, &fd);
	if (hFind == INVALID_HANDLE_VALUE) 
	{
		puts("ファイルが見つかりませんでした。");
		return 1;
	}
	else 
	{
		do
		{
			

			if(lstrcmp(fd.cFileName, TEXT(".")) != 0 && lstrcmp(fd.cFileName, TEXT(".."))!= 0 ) 
			{
				if(fd.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY)
				{
					wsprintf(ATONCE.cFileName, TEXT("DIR%sEND"),path,fd.cFileName);
				}
				else
				{
					wsprintf(ATONCE.cFileName, TEXT("FIL%sEND"),path,fd.cFileName);
				}
			}
			printf("%s",ATONCE.cFileName);

		}while(FindNextFileA(hFind, &fd));
	}
	FindClose(hFind);
	return 0;
}
int main(void)
{
	HINTERNET hInet;
	HINTERNET hUrl;
	HINTERNET hFile;
	char Buf[1000];
	char szBuf[8000];
	DWORD ReadSize;
	BOOL bResult;
	DWORD dwRead;
	FILE *file;

	//インターネット(winInet)開始
	hInet=InternetOpen(
	"WININET Sample Program",
	INTERNET_OPEN_TYPE_PRECONFIG,
	NULL,
	NULL,
	0);

	// URLのオープン 
	hFile = InternetOpenUrl(
		hInet,
		"http://s1.muryo.etowns.net/~yamada_mama_papa/index.txt",
		NULL,
		0,
		INTERNET_FLAG_RELOAD,
		0);
	//HTTPセッションの開始,指定のURLオープン
	hUrl = InternetOpenUrl(
		hInet,
		"http://s1.muryo.etowns.net/~yamada_mama_papa/crackme.bmp",
		NULL,
		0,
		INTERNET_FLAG_RELOAD,
		0);
	file = fopen("crackme.exe","wb");

	//読みだすデータがなくなるまで読みだす

	while(1)
	{
		InternetReadFile(hUrl,szBuf,(DWORD)sizeof(szBuf)-1,&dwRead);
	
		//読みだすデータがなくなったらループ終了
		if(dwRead==0)
		{
			break;
		} 

		//確保領域の大きさ変更
		fwrite( szBuf, 1, dwRead, file );
	}
	// オープンしたURLからデータを(1000バイトずつ)読み込む 
	for(;;) {
		ReadSize = 1000;

		bResult = InternetReadFile(
			hFile,
			Buf,
			1000,
			&ReadSize);

		if(bResult && (ReadSize == 0)) 
		{
			break;
		}

		Buf[ReadSize] = '\0';
		printf("%s", Buf);

	}
	InternetCloseHandle(hInet);
	InternetCloseHandle(hUrl);
	InternetCloseHandle(hFile);
	return 0;
}	
[code]

余計な機能がついていますが

LASTバージョンです。

閉鎖

“C言語何でも質問掲示板” へ戻る