• 締切済み

C++

ICPCの過去問です。 問題文:http://www.deqnotes.net/acmicpc/p0003/ja 過去問を解いたのですが実行が上手くいかずに困っています。 私の書いたソースコード: #include <iostream> #include <string> using namespace std; class Line{ public: char* Read(){ char number[1024];//数字を入れる配列 static char sentence[76];//できあがった文字列を入れる配列 char word;//現在の文字 int i=0;//カウンタ int s=0;//sentenceのカウンタ int y=0;//数字が何回連続したかを数える char one[5]={'.',',','!','?',' '}; char two[3]={'a','b','c'}; char three[3]={'d','e','f'}; char four[3]={'g','h','i'}; char five[3]={'j','k','l'}; char six[3]={'m','n','o'}; char seven[4]={'p','q','r','s'}; char eight[3]={'t','u','v'}; char nine[4]={'w','x','y','z'}; int c; while(c = getchar() != '\n'){//数を一文字ずつ配列にいれていく number[i] = c; i++; } for(int x=0;x<(i+1);x++){ if(number[x]=='0'){ if(word == 'N'){} else{sentence[s]=word;s++;y=0;word='N';} } else{ if(number[x]=='1'){ word=one[y]; y++; y=y%5;} else if(number[x]=='2'){ word=two[y]; y++; y=y%3;} else if(number[x]=='3'){ word=three[y]; y++; y=y%3; } else if(number[x]=='4'){ word=four[y]; y++; y=y%3; } else if(number[x]=='5'){ word=five[y]; y++; y=y%3; } else if(number[x]=='6'){ word=six[y]; y++; y=y%3; } else if(number[x]=='7'){ word=seven[y]; y++; y=y%4; } else if(number[x]=='8'){ word=eight[y]; y++; y=y%3; } else{ word=nine[y]; y++; y=y%4; } } } sentence[i]='N'; return sentence;//配列の先頭のポインタを返す } }; int main(){ int n;//行数 cin>>n; getchar();//改行をとる char *first[n]; int i; int x=0; char ch; char *Fir; for(i=0;i<n;i++){ Line line; first[i] = line.Read(); } for(int j=0;j<i;j++){ Fir = first[i]; while((ch = Fir[x]) != 'N'){ cout << ch ; x++; } cout << '\n'; } return 0; } 実行結果: 1 20 Segmentation fault となってしまいます。 coutやコメントアウトで動きを追ってみたところ、下から8行目くらいのwhile文がなければ、segumentation faultはおきませんでした。ポインタの扱いが間違っているのかなとは思うのですが、どこが悪いのか考えても分かりません。どなたか教えてください。

みんなの回答

  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.3

問題文(リンク先)と、Line::Read()をみました。 最大1024文字と規定されているようですから、getchar()で読み込むのではなく、バッファに一度に読み込んでもようかと思われます。 # C++ですから…cin.getline()で読み込みでしょうかね。 ちなみに、#1さんの指摘を修正したとしてgetchar()で読み込む現在の方法では バッファサイズを越えるコトが可能です。 # まぁ、現実的には1024以上の入力が必要ですけどね。 >char one[5]={'.',',','!','?',' '}; >char two[3]={'a','b','c'}; >char three[3]={'d','e','f'}; >char four[3]={'g','h','i'}; >char five[3]={'j','k','l'}; >char six[3]={'m','n','o'}; >char seven[4]={'p','q','r','s'}; >char eight[3]={'t','u','v'}; >char nine[4]={'w','x','y','z'}; 私なら二次元配列でしょうかねぇ。 char trans[9][6] = {  {'.',',','!','?',' '},  {'a','b','c'},  {'d','e','f'},  {'g','h','i'},  {'j','k','l'},  {'m','n','o'},  {'p','q','r','s'},  {'t','u','v'},  {'w','x','y','z'}  }; って感じで。 入力された数字を数値変換して、添え字に使用ですかね。 '1'がnumに入力されたならtrans[(num - '1')][]とか。 1文字ずつ確認して行って…回数をxとすると、trans[('1' - '1')][x]が'\0'だったらxを0に戻します。 これならone[]を参照するのか、two[]を参照するのか…の分岐が不要です。 # if(number[x]=='~'){並べるより、switch()の方がよさそうですけど…。 '0'で確定後に'1'~'9'が未入力だったかどうか? とか、数字以外が入ってきたらどうするか? 等のエラー処理も必要かも知れませんが。 # 前者は0の入力が続く…という入力例に対応する為。後者は念のため。

  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.2

C/C++のカテゴリあるんですけどね。 なお、Line::Read()の中はそれほど追っていません。 >for(i=0;i<n;i++){ >Line line; >first[i] = line.Read(); >} ここでfirst[0]からfirst[n-1]までに入るアドレスが異なっているか…とか確認してます? # Line::Read()内のstatic char sentence[76];は同じアドレスなんではないですかね? そして、ココで作成したインスタンスの寿命が尽きた後でも参照したりしませんか? # staticだから一応残っているのかなぁ……。 んで、ここのforループが終わったときのiの値はいくつになっているでしょう? nに1を入れた、ということは、first[0]しかありませんね。 で、ループ終了時にiは1になっているかと。 >for(int j=0;j<i;j++){ >Fir = first[i]; Firに入れているのはfirst[1]になります。 first[]で使える添え字は0だけのハズなのに。です。 おめでとう!バッファオーバーランを達成してSegmentation faultです。 # Fir = first[i];のiはjの誤りでしょう。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

たくさんあります。 c = getchar() != '\n' これは c = (getchar() != '\n') (c = getchar() ) != '\n' のどちらだと思ってますか? 演算子の優先順位を確認しましょう if(word == 'N'){} wordが初期化されず使われる可能性があります。 for(i=0;i<n;i++){ Line line; first[i] = line.Read(); printf("first[%d]=%p\n",i,first[i]); // を追加して } として、実行してみてください。 これが何を意味するか、考えてみてください。

関連するQ&A