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

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

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

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

Q&A

解決済

5回答

348閲覧

メモリの動的な割り当てにおいて意図しない領域を参照する原因について

yuChem

総合スコア12

C

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

0グッド

3クリップ

投稿2018/02/19 19:33

### 前提
はじめまして
現在、大規模データ解析用のプログラムをC言語で書いています。以下のようなメモリの動的な割り当てを行い、データを読み込む部分を作成しました。
プログラムを実行するサーバー(128GBのメモリを搭載)は、以下のソースコードから生成されるプログラムが要求するメモリの容量の領域を確保できると判断しています。OSはCentOS6.5で、コンパイルなどはgccで行っています。

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

以下のコードにあるようにmallocで別々に確保した領域にデータを書き込むように設計したのですが、datahe[i]のポインタが示す領域にデータを書き込んだにも関わらず、datage[i] (i>300000以降)のポインタが示す領域にデータが書き込まれ、//datage loading data//で示す部分で読み込まれたデータか書き換えられてしまいます。原因の究明を行っているのですが現在、解決に至っていません。 
//memory allocation// の部分にあるprintfで表示するようにしているerror1, 2, 3は表示されませんでした。
経験が浅いため、原因を突き止めるのに必要な情報が欠けている可能性があることご了承ください。また、情報が欠けている場合、ご教示いただけると幸いです。

該当のソースコード

C

1int main() 2{ 3//memory allocation// 4char *datahe[500000]; 5int i; 6int i2; 7 for (i = 0; i < 500000; i++) 8 { 9 datahe[i] = NULL; 10 datahe[i]=(char *)malloc(1000); 11 if (datahe[i] == NULL) 12 { 13 printf("error1\n"); 14 } 15 } 16 17char *datage[300000]; 18 for (i = 0; i < 300000; i++) 19 { 20 datage[i] = NULL; 21 datage[i]=(char *)malloc(1000); 22 if (datage[i] == NULL) 23 { 24 printf("error2\n"); 25 } 26 } 27 for (i = 0; i < 300000; i++) 28 { 29 for (i2 = 0; i2 < 500000; i2++) 30 { 31 if(datage[i] == datahe[i2]) 32 { 33 printf("error3\n"); 34 } 35 } 36 } 37 38char listtad[30000][100] = {}; 39char extract[50][300] = {}; 40char *ret; 41 42FILE *fpi; 43FILE *fpi2; 44FILE *fpo; 45long ili = 0; 46long ige = 0; 47long ihe = 0; 48long ilip = 0; 49long j = 0; 50long ip = 0; 51long jp = 0; 52long jp2 = 0; 53int jug = 0; 54int nr = 0; 55// list loding data // 56if ((fpi = fopen("./input_data/list_CC.txt","r")) == NULL) 57 { 58 printf("error read file 0\n"); 59 }else{ 60 jug = 1; 61 while (fgets(listtad[ili],100,fpi) != NULL) 62 { 63 ili++; 64 } 65 fclose(fpi); 66 } 67// datage loading data // 68if ((fpi = fopen("./input_data/GE_and_CC.txt","r")) == NULL) 69 { 70 printf("error read file 1\n"); 71 jug = 0; 72 }else{ 73 while (fgets(datage[ige],1000,fpi) != NULL) 74 { 75 nr = 0; 76 while((datage[ige][nr] != '\n') && (nr < 1000)) 77 { 78 nr++; 79 } 80 datage[ige][nr] = '\0'; 81 ige++; 82 } 83 fclose(fpi); 84 } 85// datahe loading data // 86if ((fpi2 = fopen("./input_data/HE_and_CC.txt","r")) == NULL) 87 { 88 printf("error read file 2\n"); 89 jug = 0; 90 }else{ 91 while (fgets(datahe[ihe],1000,fpi2) != NULL) 92 { 93 nr = 0; 94 while((datahe[ihe][nr] != '\n') && (nr < 1000)) 95 { 96 nr++; 97 } 98 datahe[ihe][nr] = '\0'; 99 ihe++; 100 if (ihe == 499999) 101 { 102// data analysis part// 103 ...... 104// part end // 105 ihe = 0; 106 } 107 } 108 } 109

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

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

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

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

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

guest

回答5

0

ベストアンサー

直接的な原因はわかりませんでした。
cateyeさん同様、スタック領域が不足している可能性があります。
以下3つの変数を関数の外に出してグローバル変数にするか、staticを付加するか、どちらかを試してみてください。

c

1 char *datahe[500000]; 2 char *datage[300000]; 3 char listtad[30000][100] = {}; 4

投稿2018/02/19 23:54

ttyp03

総合スコア16998

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

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

yuChem

2018/02/20 15:43

ttyp03さん、ご回答ありがとうございます。 ttyp03さんからご助言いただきましたstaticを付加する方法で解決致しました。
guest

0

直接の回答ではありません。
ポインタ領域(dataheなど)がかなり大きいようですが、gccのオプションでスタックサイズは拡張してありますか?

投稿2018/02/19 20:21

cateye

総合スコア6851

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

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

yuChem

2018/02/20 15:42

ご回答ありがとうございます。結論から申し上げますと、ttyp03さんのstaticを付加する形で解決しました。cateyeさんからご助言いただきましたgccのオプションでスタックサイズを拡張する方法もやってみたのですが、gcc -Wl,stack,10240(stack size)を実行すると以下のようなメッセージが出て、正常に終了されませんでした。以下の生じた問題については後日調べようと思っています。 もし、再びご助言いただけると幸いではあります。 gcc -Wl,--stack,10240 file.c /usr/bin/ld: stack: No such file: No such file or directory collect2: ld はステータス 1 で終了しました
yuChem

2018/02/20 23:45

ご回答ありがとうございました。今後の参考にさせていただきます。
guest

0

恐らくdatage,dataheスタック上に連続して確保されていると思います
コンパイラーの最適化などによっては、どのようになるか、わかりませんが、
後で宣言されたものが若いアドレスに配置されることが多いです。
なのでdatageのサイズを超えたアクセスによって後ろのdataheを見てしまっていると思われます。

C

1#include <stdio.h> 2 3int main() 4{ 5 int i; 6 int a[4]; 7 int b[4]; 8 for(i=0;i<4;i++)a[i]=b[i]=0; 9 10 a[0]=123; 11 printf("%d",b[4]); 12 13 return 0; 14}

b[4]なんてありませんが、123と表示されます。(VCで確認)

投稿2018/02/20 06:12

編集2018/02/20 06:15
tmp

総合スコア277

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

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

yuChem

2018/02/20 16:04

tmpさん 実例を示していただきましてありがとうございます。参考になります。 今回のトラブルを教訓として、スタックなどの基本的な部分に注意してプログラムを設計するように努めたいと思います。ありがとうございました。
guest

0

while (fgets(listtad[ili],100,fpi) != NULL)

こいつがスタック上のカウンタ(long ixx)を上書しているのでは?
上記の処理では、読み込みファイルに改行も含めて100Byte以上の行があると、100Byte以降は次の読み込みに回されます。その場合、iliが30000以上になる可能性があります。

fgets(3)を使用するときは十分な長さのバッファに読み込んで、チェック後に実際の変数にコピーしましょう。

投稿2018/02/20 01:24

hichon

総合スコア5737

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

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

yuChem

2018/02/20 16:01

hichonさん ご助言ありがとうございます。 while (fgets(listtad[ili],100,fpi) != NULL)は問題ないようでしたが、今後、fgetsを用いる際には十分な長さのバッファを用いて用心しようと思います。
guest

0

datahe[i]のポインタが示す領域にデータを書き込んだにも関わらず、
datage[i] (i>300000以降)のポインタが示す領域にデータが書き込まれ

ここが理解できませんでした。
dataheiに何かを書き込んだら、*datage[i] == *datahe[i]となるのですか?
datageiは存在しないはずですが。
datahe[i]と同じ値がdatageの何処かに書き込まれる?

もし対応するインデックス等がわかるならば書いてあった方が親切かもしれません。

投稿2018/02/20 00:16

moredeep

総合スコア1507

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

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

yuChem

2018/02/20 15:58

more deepさん、返信ありがとうございます。 ご指摘の通り、datage[i](i>300000)の記載は誤りです。 正確な記述ができていないようで申し訳けありませんでした。 *datage[i] (i > x, xの値が実行の度に同じ値を示すのかを検証していない。少なくとも特定のx以上)の要素が後で実行されるdataheへの書き込みによって変更される現象が見られました。 staticを付加することで、異常が見られなくなりましたのでスタック領域の不足が問題のようでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問