• 締切済み

セグメントエラー

#include<stdio.h> #include<ctype.h> #include<string.h> #define MAX_BYTE_SIZE 256 #define JUDGMENT_CODE 1 #define FILE_NAME 2 void Decoding(unsigned char cript[], unsigned char plain[], unsigned char shift) { FILE *fout; int i; if((fout = fopen("decode.txt", "w"))==NULL) { printf("File cannot be opend. \n"); exit(1); } printf("\nPlaintext : %s\n", plain); fprintf(fout, "\nPlaintext : %s\n", plain); for(shift=1; shift<26; shift++) { for(i=0; plain[i]!='\0'; i++) { if(plain[i]>0x60 && plain[i]<0x7b) //if(isalpha(plain[i])) { cript[i]= plain[i]+ shift; if(cript[i] > 0x7a) { cript[i] = cript[i] - 26; } } else { cript[i] = plain[i]; } } cript[i]= '\0'; printf("(%d) : %s", shift, cript); fprintf(fout, "(%d) : %s", shift, cript); } fclose(fout); } void Encoding(unsigned char cript[], unsigned char plain[], unsigned char shift) { FILE *fout; int i; if((fout = fopen("encode.txt", "w"))==NULL) { printf("File cannot be opend. \n"); exit(1); } printf("\nPlaintext : %s\n", plain); fprintf(fout, "\nPlaintext : %s\n", plain); printf("暗号化するときのずらす文字数を入力してください\n"); scanf("%d", &shift); for(i=0; plain[i]!='\0'; i++) { if(plain[i]>0x60 && plain[i]<0x7b) //if(isalpha(plain[i])) { cript[i]= plain[i]+ shift; if(cript[i] > 0x7a) { cript[i] = cript[i] - 26; } } else if(plain[i]>0x40 && plain[i]<0x5b) { cript[i]= plain[i] + 32 + shift; if(cript[i] > 0x7a) { cript[i] = cript[i] - 26; } } else { cript[i] = plain[i]; } } printf("暗号化すると%s", cript); fprintf(fout, "文字数を %d ずらして暗号化すると\n %s", shift, cript); fclose(fout); } int main(int argc, char *argv[]) { FILE *fin; unsigned char plain[MAX_BYTE_SIZE]; unsigned char cript[MAX_BYTE_SIZE]; unsigned char shift; if((fin = fopen(argv[FILE_NAME], "r"))==NULL) { printf("File cannot be opend. \n"); exit(1); } if(strcmp(argv[JUDGMENT_CODE], "-D")==0) { fgets(plain, MAX_BYTE_SIZE, fin); Decoding(cript, plain, shift); } else if(strcmp(argv[JUDGMENT_CODE], "-E")==0) { fgets(plain, MAX_BYTE_SIZE, fin); Encoding(cript, plain, shift); } fclose(fin); return 0; } を6で実行すると % ./a.out -E plaintext.txt Plaintext : toward next generation robotics that supports human future 暗号化するときのずらす文字数を入力してください 6 暗号化するとzucgxj tkdz mktkxgzout xuhuzoiy zngz yavvuxzy nasgt lazaxk セグメントエラー となってしまいます。どうしたらセグメントエラーが出てこないようにできますか。

みんなの回答

  • arain
  • ベストアンサー率27% (292/1049)
回答No.2

No.1ですが…… ・出力バッファの(NULL文字での)初期化 ・文字列の終端には必ずNULL文字を入れる あと、ループ処理も問題あり。 ・「MAX_BYTE_SIZE -1」文字分でループを止める処理が必要。 に対して、 >どのようにプログラムを書き直したらよいのでしょうか。 >初心者にでも簡単にわかるように教えてもらえたら幸いです と返されると、「『理解して』プログラム作ってますか?」 と逆に問いたくなります。 「短いプログラムだから」と端折らずに、「何をやっている(つもり)」かはコメントは一緒に記述していくと、問題点がわかりやすくなりますよ。 小言はここまでとして、 「文字列」の前提として「NULL文字まで」を文字列して扱うため、文字列操作用のバッファは 使用する前に「NULL文字」で初期化しておけば(バッファサイズ-1)までであれば最低限の暴走は防げます。 ・出力バッファの(NULL文字での)初期化 は  memset( cript, '\0', MAX_BYTE_SIZE ); のように初期化する。 同様に、「文字列」として扱いための重要なところが抜けている変換処理は、 ・文字列の終端には必ずNULL文字を入れる ・「MAX_BYTE_SIZE -1」文字分でループを止める処理が必要。  for(i=0; plain[i]!='\0'; i++)  {  …  } を  for( i = 0; (plain[i] != '\0') && (i < (MAX_BYTE_SIZE -1)) ; i++ )  {  …  } cript[i] = '\0'; とすれば、変換後の文字の後ろにNULL文字が入りそこまでを文字列として扱い、 バッファを超えてのアクセスによるメモリエラー(今回はセグメンテーションエラー) もなくなります。 そうそう、今回とは直接関係ありませんが、関数リファレンスに記載されている「引数の型」もしっかり理解した方がいいでしょう。 fgets()のリファレンスは char *fgets( char *s, int n, FILE *stream ) なので、「引数の型が違う」とワーニングエラーは出てるはずです。 コンパイルはでき、プログラム自体は動作するとしても、あとあとこの部分で痛い目にあうこともありますよ。

  • arain
  • ベストアンサー率27% (292/1049)
回答No.1

簡単に書くと出力用バッファ「文字列の終端」がないから、終端扱いされる文字列が出でくるまで表示しようとして、 とんでもないところまでいきついてメモリセグメンテーションでエラーをおこしてる。 ・出力バッファの(NULL文字での)初期化 ・文字列の終端には必ずNULL文字を入れる あと、ループ処理も問題あり。 仮にNULL文字が入力バッファ内に存在しない場合ループが終了しない(もしくはその先のNULL文字扱いされるメモリまで参照する)。 当然出力バッファに連続するメモリ領域も破壊されるので ・「MAX_BYTE_SIZE -1」文字分でループを止める処理が必要。  (最後には「必ず」NULL文字を入れる必要があるため)

rr006086
質問者

補足

どのようにプログラムを書き直したらよいのでしょうか。 初心者にでも簡単にわかるように教えてもらえたら幸いです

関連するQ&A