ページ 1 / 1
fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月02日(月) 11:28
by helloworld1853
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);
}
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月02日(月) 14:12
by shiro4ao
試してみたところ
私の環境では以下のダイアログが出てきました・・・・
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関数に読み込み要素数を伝えてあげる必要がありありそうです
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月02日(月) 15:27
by box
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回連続で実行している理由を教えてください。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月02日(月) 23:23
by helloworld1853
不具合がたくさん見つかったので大幅に修正します。
ソースコードを見やすくしました。
コード:
//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;
}
先ほど皆様に報告された不具合は修正しました。
しかしそれでうまくいきません。
仕様でしょうか。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月02日(月) 23:42
by box
helloworld1853 さんが書きました:
しかしそれでうまくいきません。
どのようにうまくいかないかを書くことは可能でしょうか。
helloworld1853 さんが書きました:
仕様でしょうか。
何の仕様であると思われているのでしょうか。
まあ、プログラムというものは、思った通りには動かないものです。
書いたとおりに動きます。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月03日(火) 00:42
by helloworld1853
不思議なことにソースコードをまったくいじくっていないにもかかわらず
ビルドする度に結果が違うのです。
あるときは 唖C だったりまたあるときは リxH だったりと
ランダムです。 ただ 文字が三文字ぐらいに収まっています。
バイナリエディタで詳しく調べようかと考えています。
初めての体験なのでかなりパニクっています。
検索してもまったく見つかりませんですし・・・
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月03日(火) 06:47
by beatle
毎回文字が変わるのは、恐らく変なメモリ領域を読み込んでファイルに書いているせいです。
helloworld1853さんが本当に問題を解決したいならば、回答者の皆さんの発言、特に今回ならshiro4aoとboxさんの発言をちゃんと読むことです。
読んでいるのかもしれませんが、shiro4aoさんとboxさんの発言に対する反応がまったくありません。外野から見ると無視している印象を受けます。
さて、helloworld1853さんのコードを見ると、ポインタ周りの取り扱いが苦手に見えます。
以下のコード、実行せずに出力結果を予想することはできるでしょうか?
コード:
char s[100], *p;
p = s;
printf("%d\n", sizeof(s));
printf("%d\n", sizeof(p));
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月03日(火) 14:18
by box
Windowsとかインターネットとか、余分な要素を取り除いて、
ローカルにあるテキストファイルをfwriteする、というような
単純なプログラムで検証してみてはどうでしょうか。
原因がどこにあるかを切り分けることから始める必要がありそうです。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月03日(火) 22:55
by helloworld1853
>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]
こんな感じでいいでしょうか。
ご指摘がある通り僕はポインタがあまりできていないので
まだ変な所があるかもしれません。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月04日(水) 06:39
by beatle
bufはintの配列であって、それをそのままfwirteしていますから、{0x00000054, 0x00000045, ...}というデータが書き出されています。
8文字の他に、24バイトのナル文字が書き出されているわけですね。
僕の、「無視している」という指摘に対して反応してもらったのはいいのですが、僕のNo.7の質問には答えてもらっていないようです。
helloworld1853さんが陥っている問題を極力シンプルにして出題したつもりですので、是非答えて下さい。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月04日(水) 09:07
by helloworld1853
僕は、100だと思いました。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月04日(水) 09:39
by beatle
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にポインタ変数を指定して、そのポインタ変数が指し示している変数の大きさを取得しようとするミスは、よく目にしますのでご注意下さい。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月04日(水) 12:15
by helloworld1853
なるほど!!
よく分かりました。
改めて僕のソースコードを見ますと・・・
おお・・・ fwriteの箇所が間違っていたのか・・・
fwrite(IpszSrc,dwTotal,1,file);
に修正した結果 動作しました。
皆様のおかげです。
その他小さい疑問があるので 皆様に聞いてみたいと思います。
まず、コンパイルするとfopen,strcatではなくfopen_s,strcat_sをつかえと出てきます。
たぶんオーバーフローを防ぐ?目的だと思いますが、
fopen_s,strcat_sを使えば文字が707000文字あっても無事に動作するのでしょうか。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月05日(木) 12:03
by helloworld1853
自己解決しました。
ありがとうございます。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月05日(木) 14:18
by asd
helloworld1853 さんが書きました:自己解決しました。
ありがとうございます。
できれば、どのように解決したのかを明記してください。
同じ問題で困っている方が出たときのためによろしくお願いします。
---フォーラムルールから引用---
また、解決した時は、「解決しました」とだけ言って去らず、ソースコードや解決した方法を明記して下さい。
同じ事で困っている人の為に過去ログに有用な情報を残すようお願いします。
Re: fwriteを使うと謎の文字列が追加される。
Posted: 2012年4月12日(木) 20:39
by helloworld1853
コード:
#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バージョンです。