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

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

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

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

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

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

Q&A

解決済

2回答

6600閲覧

例外がスロー ブレークポイントが発生しました ヒープが原因かなと考えています。

shunxile

総合スコア26

C

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

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

配列

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

0グッド

0クリップ

投稿2021/05/11 01:46

前提・実現したいこと

C言語初心者です。
指定ファイル内を探索してディレクトリ・ファイル名を出力するシステムを作成しています。
現状ブレークポイントが発生しました。と出ますがCSV出力されている状態です。
また出力の際正常に対象全てのデータが出力されることもあれば途中まで出力されることもあります。
(Sample2やSample4で終わったりしています。)
検索してみるとヒープが破壊されていることが原因なのかなと考えているのですが
どのように修正すればよいか分からないといった状況です。
よろしくお願いいたします。

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

例外が発生しました。 file_search.exe によってブレークポイントが発生しました。

該当のソースコード

Sampleファイル https://gyazo.com/c8e4387bf035c97eeb96ad42b844f837 呼び出し履歴 https://gyazo.com/936af4fdc360b075db5ccbcc9a031a44 ブレークポイント発生箇所(exe_common.inl) https://gyazo.com/1ab31c3a03fc8af1fb0fa9a2524ec853

C

1main.c 2#define _CRT_SECURE_NO_WARNINGS 3 4#include <Windows.h> 5#include <stdio.h> 6#include <locale.h> 7#include <stdlib.h> 8#include <io.h> 9#include <sys/stat.h> 10#include <direct.h> 11#include <string.h> 12#include <wchar.h> 13#include <limits.h> 14 15void FileSearch(const wchar_t* dirpath, int count); 16char file_name[1024]; 17const char output_dir[1024]; 18FILE* file; 19 20int main(int argc, char* argv[]) 21{ 22 // 絶対パスの分割と取得 23 char* search_file = argv[1]; 24 25 char path_dir[1024] = { '\0' }; 26 char* dirend; 27 28 dirend = strrchr(search_file, '\'); 29 dirend = dirend + 1; 30 31 for (int n = 0; n < (int)strlen(search_file); n++) 32 { 33 path_dir[n] = search_file[n]; 34 if (search_file + n == dirend - 1) 35 { 36 break; 37 } 38 } 39 40 // パスの変数化 41 sprintf(file_name, "%sOutput/output.csv", path_dir); 42 sprintf(output_dir, "%sOutput", path_dir); 43 strcat(path_dir, dirend); 44 sprintf(path_dir,"%s\\", path_dir); 45 46 //システム既定のロケールに設定する 47 setlocale(LC_ALL, ""); 48 //マルチバイト文字をワイド文字に変換 49 wchar_t* wide_path_dir[1024]; 50 mbstowcs(wide_path_dir, path_dir, sizeof(wide_path_dir) / sizeof(wide_path_dir[0])); 51 52 if (argc > 1) 53 { 54 // Outputディレクトリがデスクトップに存在するか確認 55 struct stat output; 56 int existence = stat(output_dir, &output); 57 // Outputディレクトリがなかった時作成する 58 if (existence != 0) 59 { 60 (void)_mkdir(output_dir); 61 } 62 63 file = fopen(file_name, "w"); 64 fprintf(file, "%s\n", dirend); 65 fclose(file); 66 } 67 68 // ディレクトリ名とファイル名、ファイルサイズを表示する 69 FileSearch(wide_path_dir, 1); 70 return 0; 71} 72 73 74// 引数として渡したディレクトリ以下のディレクトリとファイルを全て表示する 75void FileSearch(const wchar_t* dirpath, int count) 76{ 77 78 long long int size = 0; 79 int i = 0; 80 int datasize = 0; 81 int pathsize = 0; 82 83 // ハンドル 84 HANDLE hFind; 85 // ファイル情報 86 WIN32_FIND_DATA win32fd; 87 88 datasize = sizeof(win32fd); 89 90 // ディレクトリにワイルドカードを追加 91 // ファイル名も含んだパス 92 wchar_t* dirwildpath; 93 dirwildpath = (wchar_t*)malloc(sizeof(wchar_t) * datasize); 94 // ファイルパスをコピー 95 wcscpy(dirwildpath, dirpath); 96 // ワイルドカードを追加 97 wcscat(dirwildpath, L"*"); 98 99 // ハンドルを取得しファイル情報を保存する 100 hFind = FindFirstFile(dirwildpath, &win32fd); 101 102 // 何も見つからなかったとき 103 if (hFind == INVALID_HANDLE_VALUE) { 104 FindClose(hFind); 105 return; 106 } 107 free(dirwildpath); 108 while (FindNextFile(hFind, &win32fd)) 109 { 110 // カレントディレクトリと親ディレクトリのときは何もしない 111 if (wcscmp(win32fd.cFileName, L".") == 0 112 || wcscmp(win32fd.cFileName, L"..") == 0 || wcscmp(win32fd.cFileName, L"desktop.ini") == 0) 113 { 114 continue; 115 } 116 117 // ディレクトリのときの処理 118 else if (win32fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) 119 { 120 file = fopen(file_name, "a"); 121 for (i = 0; i < count; i++) 122 { 123 fprintf(file, ","); 124 } 125 fwprintf(file, L"%ls\n", win32fd.cFileName); 126 fclose(file); 127 128 // 文字列バッファを更新 129 pathsize = sizeof(dirpath); 130 wchar_t* dir_buf = (wchar_t*)malloc(sizeof(wchar_t) * pathsize); 131 /*if (count > 1) 132 { 133 free(dir_buf[count - 1]); 134 }*/ 135 136 // ディレクトリをコピーする 137 wcscpy(dir_buf, dirpath); 138 wcscat(dir_buf, win32fd.cFileName); 139 wcscat(dir_buf, L"\"); 140 // 再帰する 141 FileSearch(dir_buf, count + 1); 142 } 143 else 144 { 145 // ファイルのとき 146 file = fopen(file_name, "a"); 147 long long int fsize = fseek(file, 0, SEEK_END); 148 fgetpos(file, &size); 149 fseek(file, fsize, SEEK_SET); 150 for (i = 0; i < count; i++) 151 { 152 fprintf(file, ","); 153 } 154 fwprintf(file, L"%ls,%lld[byte]\n", win32fd.cFileName, size); 155 fclose(file); 156 } 157 } 158 FindClose(hFind); 159} 160 161

試したこと

動的配列のdirwildpathをFindClose(hFind)の前で解放してみたが変化なし
dir_bufはどのタイミングで解放していいか分かりません。

補足情報(FW/ツールのバージョンなど)

Windows10
Microsoft Visual C++ 2019

不足情報あれば随時追加させていただきます。

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

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

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

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

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

guest

回答2

0

ベストアンサー

c

1 WIN32_FIND_DATA win32fd; 2 3 datasize = sizeof(win32fd); 4 5 // ディレクトリにワイルドカードを追加 6 // ファイル名も含んだパス 7 wchar_t* dirwildpath; 8 dirwildpath = (wchar_t*)malloc(sizeof(wchar_t) * datasize);

ここで sizeof(wchar_t) * datasize としているのは妙です。dirwildpath に入れたいデータサイズと WIN32_FIND_DATA のサイズは関係がありません。sizeof(wchar_t) * (wcslen(dirpath) + 2) ではないでしょうか。
(とは言え、WIN32_FIND_DATA はかなり大きいので、ここが原因で問題が起きているわけではないと思います。)

c

1 pathsize = sizeof(dirpath); 2 wchar_t* dir_buf = (wchar_t*)malloc(sizeof(wchar_t) * pathsize);

pathsize がポインタのサイズ(4 か 8 でしょう)になっています。そのため高い確率でバッファオーバーランしています。これも wcslen(dirpath) + wcslen(win32fd.cFileName) + 2 のようにすべきです。

  • Cで文字列操作するのは間違いやすいので、C++でstd::wstringを活用するのをおすすめします。
  • 極端に長い・深いパスを扱わなくてもよいなら、ファイル名用バッファのサイズを FILENAME_MAX などでの固定長にして、この長さを超えそうなら処理しない、というのも手です。

投稿2021/05/11 02:13

編集2021/05/11 02:41
int32_t

総合スコア21190

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

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

shunxile

2021/05/11 02:53

>>int32_tさん 回答ありがとうございます。 修正したところ改善され出力されました。ありがとうございます。 いろいろと理解しきれてないことがあるのが分かりました。 +2というのはワイド文字の2バイトとワイルドカードの『¥』1文字ということで2×1ということでしょうか?
int32_t

2021/05/11 03:01

+2 は、追加する '*' か '\' のぶんと、文字列終端の '\0' のぶんです。
shunxile

2021/05/11 03:10

>>int32_tさん そういうことでしたか!ありがとうございます。 またFILENAME_MAXやstd::wstringなど知らないことだらけで すごく勉強になりました。 個人的にもCの文字列に関して苦手意識もあったのですごく助かりました! ありがとうございます。
guest

0

C

1#define _CRT_SECURE_NO_WARNINGS 2 3#include <Windows.h> 4#include <stdio.h> 5#include <locale.h> 6#include <stdlib.h> 7 8void FileSearch(const wchar_t* dirpath, int depth) { 9 10 // ハンドル 11 HANDLE hFind; 12 // ファイル情報 13 WIN32_FIND_DATAW win32fd; 14 15 wchar_t* dirwildpath = (wchar_t*)malloc( (wcslen(dirpath)+2) * sizeof(wchar_t) ); 16 wsprintf(dirwildpath, L"%s*", dirpath); 17 18 hFind = FindFirstFileW(dirwildpath, &win32fd); 19 free(dirwildpath); 20 21 if (hFind == INVALID_HANDLE_VALUE) { 22 FindClose(hFind); 23 return; 24 } 25 26 do { 27 if ( wcscmp(win32fd.cFileName, L".") == 0 28 || wcscmp(win32fd.cFileName, L"..") == 0 29 || wcscmp(win32fd.cFileName, L"desktop.ini") == 0) { 30 continue; 31 } 32 33 if (win32fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { 34 for ( int i = 0; i < depth; ++i ) wprintf(L" "); 35 wprintf(L"dir.[%s]\n", win32fd.cFileName); 36 37 size_t pathsize = wcslen(dirpath) + wcslen(win32fd.cFileName) + 2; 38 wchar_t* dir_buf = (wchar_t*)malloc(sizeof(wchar_t) * pathsize); 39 wsprintf(dir_buf,L"%s%s\", dirpath, win32fd.cFileName); 40 FileSearch(dir_buf, depth+1); 41 free(dir_buf); 42 } else { 43 for (int i = 0; i < depth; ++i) wprintf(L" "); 44 wprintf(L"file[%s]\n", win32fd.cFileName); 45 } 46 } while (FindNextFileW(hFind, &win32fd)); 47 FindClose(hFind); 48} 49 50int main() { 51 setlocale(LC_ALL,"japanese"); 52 FileSearch(L".\", 0); 53 return 0; 54}

投稿2021/05/11 03:24

episteme

総合スコア16614

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問