前提・実現したいこと
エラーの解消とmalloc,reallocのメモリ解放の確認。
発生している問題・エラーメッセージ
エラーはc6385の1つで74行目でおきていて、
'pP0' から無効なデータを読み取っています: 読み取り可能なサイズは 'row*sizeof(KAKEIBO_INFO)' バイトですが、'88' バイトを読み取る可能性があります。
というエラーが出ます。
また、121行目の/**/で囲ってるfree(pP0);で動作が止まります。
該当のソースコード
c
1#define _CRT_SECURE_NO_WARNINGS 2#include<stdio.h> 3#include<string.h> 4#include<stdlib.h> 5//#include"ファイル制御.h" 6 7typedef struct { 8 char hinmoku[40]; 9 int price; 10}KAKEIBO_INFO; 11 12#define STRSIZE 40 13 14int main(void) { 15 16 KAKEIBO_INFO info = { 0,0 }; //家計簿の品目と内訳の入力用 17 KAKEIBO_INFO* pP0 = NULL; //家計簿.txtの情報を入れるポインタ 18 KAKEIBO_INFO* pP1 = NULL; //メモリ拡張用 19 20 int ret = 0; //読み込み判定 21 int i = 0, j = 0; //繰り返し処理、真偽判定 22 char str[STRSIZE]; //ファイルの文字列の格納 23 int row = 0; //ファイルの行数の格納 24 25 FILE* fp = NULL; 26 27 fopen_s(&fp, "家計簿.txt", "r+"); 28#if 1 29 if (fp != NULL) { 30 while (fgets(str, STRSIZE, fp) != NULL) { //ファイルを開けたら行数を数える。配列要素数になる。 31 printf("[%d] %s", row, str); 32 row++; 33 } 34 fseek(fp, 0, SEEK_SET); 35 } 36 37#endif // 0 38 printf("\n経費の品目の入力 = "); 39 gets_s(info.hinmoku,40); 40 41 printf("金額の入力 = "); 42 scanf_s("%d", &info.price); 43 44#if 1 45 //---------------家計簿.txtがない場合(読み込めない場合)------------------ 46 47 if (fp == NULL) { 48 49 fopen_s(&fp, "家計簿.txt", "w"); //書き込みモード 50 if (fp != NULL) { 51 52 fprintf(fp, "%s %d円", info.hinmoku, info.price); //txtに書き込む 53 printf("保存完了"); 54 fclose(fp); 55 return 0; 56 } 57 58 } 59 60 //----------------家計簿.txtがある場合----------------- 61 62 63 pP0 = (KAKEIBO_INFO*)malloc(row * sizeof(KAKEIBO_INFO)); //pP0[row]分のメモリ格納 64 if (pP0 == NULL) { 65 printf("メモリ確保失敗\n"); 66 exit(0); 67 } 68 69 if (fp == NULL) { 70 printf("読み込み失敗\n"); 71 return 0; 72 } 73 74 while (ret = fscanf(fp, "%s %d円", pP0[i].hinmoku, &pP0[i].price) != EOF) { //ファイルの読み込み(pP0[]に取り込み) 75 if (ret == 0) { 76 printf("読み込みデータなし\n"); 77 return 0; 78 } 79 i++; 80 } 81 82 fseek(fp, 0, SEEK_SET); 83 84 for ( i = 0; i < row; i++) { //新しい品目があるかチェック 85 86 if (strncmp(pP0[i].hinmoku, info.hinmoku, 40) == 0) { //既存の品目に加算 87 pP0[i].price += info.price; 88 j = 0; 89 break; 90 } 91 j++; 92 } 93 94 if (j) { 95 row++; 96 97 pP1 = (KAKEIBO_INFO*)realloc(pP0, row * sizeof(KAKEIBO_INFO)); //メモリを1つ分増やした 98 99 if (pP1 == NULL) { 100 free(pP1); 101 exit(0); 102 } 103 104 for ( i = 0; i < row; i++) { 105 106 if (i == row - 1) { //最後のインデックスに入力を代入 107 pP1[i] = info; 108 } 109 110 printf("[%d]-->%s %d\n", i, pP1[i].hinmoku, pP1[i].price); //書き込み内容表示 111 112 fprintf(fp, "%s %d円\n", pP1[i].hinmoku, pP1[i].price); //書き込み 113 114 } 115 116 fclose(fp); //ファイルを閉じる 117 118 free(pP1); //メモリ解放 119 120 /* 121 free(pP0); 122 */ 123 124 if (pP0 != pP1) { //pP0とpP1アドレスが違ってたら 125 free(pP0); 126 } 127 128 return 0; 129 130 } 131 132 for ( i = 0; i < row; i++) { 133 134 printf("[%d]-->%s %d\n", j, pP0[i].hinmoku, pP0[i].price); //書き込み内容表示 135 136 fprintf(fp, "%s %d円\n", pP0[i].hinmoku, pP0[i].price); //書き込み 137 138 } 139 140 fclose(fp); //ファイルを閉じる 141 142 free(pP0); //メモリ解放 143 144 145#endif // 0 146 147 return 0; 148}
試したこと
配列 動的確保、で検索してほかの解説サイトのプログラムも動かしてみましたが同じエラーが出るもの出ないものがあり違いがわかりませんでした。
メモリ解放について、これはデバッグするとpP0とpP1のアドレスが同じところを指しているので、順番的にpP1を解放して、また同じアドレスのpP0を解放しようとすることで既に解放してあるせいで動作が止まってしまうのかと思います。reallocは別のアドレスを返すことがあるとのことなのでfree(pP0);をいれてましたが、アドレスが同じであればpP1の解放だけで大丈夫かなとおもっております。また対策として127行目のif文をいれました。
この解釈は間違いでしょうか?
補足情報(FW/ツールのバージョンなど)
Windows 10 Home
visualstudio2019 Version 16.8.6
回答2件
あなたの回答
tips
プレビュー