こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

セグメントエラー

#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
セグメントエラー

となってしまいます。どうしたらセグメントエラーが出てこないようにできますか。

投稿日時 - 2009-01-14 18:34:36

QNo.4630112

すぐに回答ほしいです

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.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 )
なので、「引数の型が違う」とワーニングエラーは出てるはずです。
コンパイルはでき、プログラム自体は動作するとしても、あとあとこの部分で痛い目にあうこともありますよ。

投稿日時 - 2009-01-14 20:48:14

ANo.1

簡単に書くと出力用バッファ「文字列の終端」がないから、終端扱いされる文字列が出でくるまで表示しようとして、
とんでもないところまでいきついてメモリセグメンテーションでエラーをおこしてる。
・出力バッファの(NULL文字での)初期化
・文字列の終端には必ずNULL文字を入れる

あと、ループ処理も問題あり。
仮にNULL文字が入力バッファ内に存在しない場合ループが終了しない(もしくはその先のNULL文字扱いされるメモリまで参照する)。
当然出力バッファに連続するメモリ領域も破壊されるので
・「MAX_BYTE_SIZE -1」文字分でループを止める処理が必要。
 (最後には「必ず」NULL文字を入れる必要があるため)

投稿日時 - 2009-01-14 18:58:47

補足

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

投稿日時 - 2009-01-14 19:16:40

あなたにオススメの質問