• ベストアンサー

C言語での質問です。

何か文字を打ち、その後鍵(整数)を入力します。 すると、元の文字が暗号化されて表示。 というプログラムを作っています。 暗号化の具体的な方法は、 (1)、元の文を鍵の整数で分けます。 例:元の文「aiueo」鍵「2」→「ai」「ueo」 (2)、そして、分けた文を混ぜます。 文字数が多い方を先に混ぜていきます。 「ai」「ueo」→「uaeio」 (3)、この混ぜた文を暗号文として出力。 という感じのプログラムを作りたいのですが、上手く混ざらず困っています。 出力された時、上手く混ざってなかったり文字化けしてるような文字が出てきたりなど。 ソースは↓です。 #include<stdio.h> #include<string.h> int main(void) { char word[256]; char angou[256]={0}; char kari[1][256]={0}; int key,i,n,a=0,b,mae,ushiro; printf("単語を入力してください。:\n"); scanf("%s",word); printf("鍵となる整数を入力してください。:\n"); scanf("%d",&key); n=strlen(word); i=0; while(i<=key-1){ kari[0][i]=word[i];/*keyの文字数までの文字を入れる。*/ i++; } while(key-1<=n){ kari[1][a]=word[i];/*keyの文字数から最後までの文字を入れる。*/ a++; i++; } i=0; a=0; mae=strlen(kari[0]); ushiro=strlen(kari[1]); if(mae>=ushiro){/*どちらの方が文字数が多いかを比べる。*/ for(b=0;b<=n;b++){ if(b%2){ angou[b]=kari[1][a];/*奇数の時、文字数が少ない方を入れる。*/ a++; } else{ angou[b]=kari[0][i];/*偶数の時、文字数が多い方を入れる。*/ i++; } } } else if(mae<ushiro){ for(b=0;b<=n;b++){ if(b%2){ angou[b]=kari[0][a]; a++; } else{ angou[b]=kari[1][i]; i++; } } } printf("暗号文は%sです。\n",angou); return(0); } 何がおかしいでしょうか?

noname#201739
noname#201739

質問者が選んだベストアンサー

  • ベストアンサー
  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

ちょっと見ただけで気づく所は > char kari[1][256]={0}; こう宣言してるなら、 kari[1] は使っちゃだめです。 > while(key-1<=n) keyもnもループ内で変化しないから無限ループします。 aやiがどんどん増えるので最終的に変なところにアクセスして止まっているのだと思います。 あとC言語における文字列は'\0'で終端されている必要がありますが その辺は大丈夫ですか? これができてないとstrlenなどは使えませんよ。 > (1)、元の文を鍵の整数で分けます。 > 例:元の文「aiueo」鍵「2」→「ai」「ueo」 > (2)、そして、分けた文を混ぜます。 > 文字数が多い方を先に混ぜていきます。 > 「ai」「ueo」→「uaeio」 たとえば「aiueokakikukeko」に対して鍵「2」を使ったときには どういう動作を期待していますか? 「uaeiokakikukeko」だとしたら後半はそのままで暗号としてはかなり微妙ですよね。

noname#201739
質問者

お礼

指摘され気付きましたw ありがとうございます!

その他の回答 (3)

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.4

>何がおかしいでしょうか?  「おかしい」部分は、皆さんの指摘どおりです。  質問者様のソースを修正し、関数化してみました。   (BorlandC++5.5.1)  ただし、No.2 さんの「じゃ駄目でしょう」部分は、そのままです。  なお、「文字列コピー」なら、該当箇所は、    strcpy( kari[ 0 ], word );    kari[ 0 ][ key ] = '\0'; 文字列終端「のみ」    strcpy( kari[ 1 ], &word[ key ] );  と3ステップで済みます(ただし、下のソース(★)には不向き)。 +++++++++++++++++++++++++++++++++++++ ☆プログラミングでは、今回の例ですと、    ・kari に格納する部分までができた段階で、正しく格納されたかを printf で確認(◆)する。  ・いろいろな条件で確認してから、次のステップの作成に進む。  ・で、完成したら、全ての確認部分を削除する。  とすると良いかも知れません。  (細かいことですが、n は、len とかの方が・・) #include <stdio.h> #include <string.h> void Mazeru( char angou[], char kariOoi[], char kariSukunai[], int n ) {  int k = 0, i = 0;  while( k < n ){   if( '\0' != kariOoi[ i ] ){ // ★    angou[ k ] = kariOoi[ i ];    k++;   }   if( '\0' != kariSukunai[ i ] ){ // ★    angou[ k ] = kariSukunai[ i ];    k++;   }   i++;   angou[ k ] = '\0'; // 文字列終端  } } void AngouKa( int key, char word[] ) {  char angou[ 256 ];  char kari[ 2 ][ 256 ] = { { 0 }, { 0 } }; // 初期化  int i = 0, n, mae0, usr1;  n = strlen( word );  while( i < key ){ //「 i と key が等しく」なって抜ける   kari[ 0 ][ i ] = word[ i ];   i++;  }  while( i < n ){   kari[ 1 ][ i - key ] = word[ i ];   i++;  }  printf( "CHECK[0] [%s]\n", kari[ 0 ] ); // 確認◆  printf( "CHECK[1] [%s]\n", kari[ 1 ] );  mae0 = strlen( kari[ 0 ] );  usr1 = strlen( kari[ 1 ] );  if( mae0 >= usr1 ) Mazeru( angou, kari[ 0 ], kari[ 1 ], n );  if( mae0 < usr1 ) Mazeru( angou, kari[ 1 ], kari[ 0 ], n );  printf( "原文= %s 暗号文= %s 鍵= %d\n\n", word, angou, key ); } void main() {  AngouKa( 2, "aiueo" );  // 入力部省略  AngouKa( 3, "aiueo" );  AngouKa( 0, "123456789" ); } 注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。

noname#201739
質問者

お礼

まとめて頂ありがとうございます!

回答No.3

他の方も指摘してますが、 ・kariの領域が足りない([1]じゃなくて[2]) ・2個目のwhileが無限ループ(i <= n??) ・文字列の終端を'\0'としてない の部分が大問題です。 さらに、混ぜてると短い方(奇数側)が先に文字が足りなくなるはずですが、なくなった後の処理がないです。

  • t_nojiri
  • ベストアンサー率28% (595/2071)
回答No.2

char kari[1][256]={0}; で定義して、 angou[b]=kari[1][a];/*奇数の時、文字数が少ない方を入れる。*/ は、スタック破壊ですね。 後、文字列コピーするのはstrcpyで kari[0][i]=word[i];/*keyの文字数までの文字を入れる。*/ じゃ駄目でしょう。

noname#201739
質問者

お礼

解答ありがとうございます!

関連するQ&A

  • C言語のC++で質問です。

    初めまして。 学籍番号から入力した数字がいくつあるか検索して検索結果を表示するプログラムを作っているのですが、このプログラムには制約がありまして、 ・while,do~while文を使用する ・for文、配列は使えない(習っていないため) ・if文は使用可能 ずっと試行錯誤してるのですがwhile文を使って表現することができません。 どなたか分かる方いたら教えてください、よろしくお願いします。 以下プログラムソース #include<stdio.h> int main() { int no,i; int gakuseki,mono; int no1,no2,no3,no4,no5,no6,no7; int kari1,kari2,kari3,kari4,kari5,kari6,kari7; mono=0; i=1; printf("任意の数字:"); scanf("%d",&no); printf("学籍番号:"); scanf("%d",&gakuseki); kari1=gakuseki/1000000; kari2=gakuseki/100000; kari3=gakuseki/10000; kari4=gakuseki/1000; kari5=gakuseki/100; kari6=gakuseki/10; kari7=gakuseki/1; no1=kari1; no2=(kari2)-(kari1*10);  no3=(kari3)-(kari2*10); no4=(kari4)-(kari3*10); no5=(kari5)-(kari4*10); no6=(kari6)-(kari5*10); no7=(kari7)-(kari6*10);   /*学籍番号を桁ごとに分解する*/ printf("%d\n",no1);  printf("%d\n",no2); printf("%d\n",no3); printf("%d\n",no4); printf("%d\n",no5); printf("%d\n",no6); printf("%d\n",no7); /*検索*/ if(no==no1) { mono=mono+1; } if(no==no2) { mono=mono+1; } if(no==no3) { mono=mono+1; } if(no==no4) { mono=mono+1; } if(no==no5) { mono=mono+1; } if(no==no6) { mono=mono+1; } if(no==no7) { mono=mono+1; } if(mono>=1) { printf("数字%dは%d個あります\n",no,mono); } else printf("数字%dはありません\n",no); return(0); } 【実行結果】 任意の数字:3 学籍番号:0653123 0 6 5 3 1 2 3 数字1は1つあります。 【実行結果ここまで】 if文で一つ一つ書いてたらすごく長くなってしまいました。 ここをどうにかwhile文でかけたらうまくいくかもしれないのですが・・・。

  • c言語で質問なのですが

    c言語で質問なのですが 下に私の疑問点があるプログラムの一部を書き込みます。 printf("ふりがな:"); memset(p[i].huri, 0, sizeof(p[i].huri)); fgets(p[i].huri,sizeof(p[i].huri),stdin); if(strchr(p[i].huri,'\n')==NULL)//バッファ処理 { while(getchar() != '\n'); } if(p[i].huri[strlen(p[i].huri)-1]=='\n')//改行解除 { p[i].huri[strlen(p[i].huri)-1] = '\0'; } if(strlen(p[i].huri)>25) { puts("<<文字入力数が多すぎでしょうあんた>>"); puts("何かキーを押してください"); getchar(); system("cls"); continue; } ここで私は構造体配列にふりがなを登録します。 しかし25文字以上なら登録できないようにしたいのですが。 if文で制御しよう試みているのですがうまくいきません。 この場合fgetsを使った時点で格納されているのでしょうか? 結局25文字以上でも構造体配列に格納されてしまいます。 どなたか教えていただけませんでしょうか? よろしくおねがいします。

  • C言語のプログラムに関する質問です。

    C言語初心者で困っています。 SNをサンプリング数、FNをファイル数として、テキストファイルの1行目のデータ(kari[0])と2行目のデータ(kari[1])をそれぞれCH1、CH2に読み込むような以下のようなプログラムがあります。 ------------------------------------------ //読込みファイル名の設定// for(j=1;j<FN+1;j++){ sprintf(file_name,"%s%d%s",file,j,".txt"); printf("%d%s\n",j,file_name); if ((fp = fopen(file_name, "r")) == NULL){ printf("Error: Can't open file; %s\n", file_name); } //データの読込み// for(i=0;i<SN;i++){ fscanf(fp,"%lf,%lf\n",&kari[0],&kari[1]); ch1[i]=kari[0]; ch2[i]=kari[1]; } fclose(fp);       ・       ・       ・ fclose(fp); } ---------------------------------------------- しかし、テキストファイルの初めの3行には不必要な文字列が存在するため、4行目から読み込むように設定したいのですが、やり方がよく分かりません。 どのようにプログラムを書き換えれば良いか、教えていただけると助かります。 よろしくお願いします。

  • C言語 strlen 再入力を促す

    文字列の比較で、 文字列の長さが60以上の時、再入力を促します。 while文を使って書いてみたのですが、 文字列Bの入力の前に、もう一度意味もなく 「文字列Aを入力===>」が表示されたり。 文字列Aのほうが小さいのに「Aのほうが大きい」と 表示されるようになったり、変な感じです。 どなたかご指摘・ご指導のほどよろしくお願いします。 int main(void) { char moji1[100]; char moji2[100]; while(strlen(moji1)>60){     printf("文字列Aを入力===>"); scanf("%80s" ,moji1); } while(strlen(moji2)>60){     printf("文字列Bを入力===>"); scanf("%80s" ,moji2);    } if(compare(moji1,moji2)>0){ printf("===AはBより大きい===\n"); } else if(compare(moji1, moji2)<0){ printf("===AはBより小さい===\n"); } else if(compare(moji1, moji2)==0){ printf("===AとBは等しい===\n"); } return 0; } int compare(char *x, char*y) { while(*x==*y && *x!=0){ x++; y++; } return (*x-*y); }

  • C言語の文字列の取り扱いが分かりません

    こんにちは。 C言語で分からないことがあり、質問させていただきました。 学校で、文字列の取り扱いを習いました。 そこで質問なんですが、以下のソースコードをstrcpy , strcat , strcmp , strlen を使わずに書くことってできないですか? 先生に質問したところ、ポインタとかいうのを使うのだそうですが、それを使わずに書くことってできるんですか?もしよろしければお願いします。 以下のプログラムですが、ユーザーから2つの文字列を受けて、そこから4つの文字列関数を使ってみましょう、というやつです。実行結果も貼っておきますね。 #include <string.h> #include <stdio.h> int main(void) { char str1[80], str2[80]; int i; printf("INPUT 1st word-line. : "); gets(str1); printf("INPUT 2nd word-line. : "); gets(str2); /*文字列(word-line)の長さを確認します。*/ printf("%s is %d moji long.\n", str1, strlen(str1)); printf("%s is %d moji long.\n", str2, strlen(str2)); /*文字列を比較します。*/ i = strcmp(str1, str2); if (!i) printf("two word-lines are same length.\n"); else if (i < 0) printf("%s is smaller than %s.\n", str1, str2); else printf("%s is bigger than %s.\n", str1, str2); /*十分なスペースがあるのなら、str2をstr1の最後に結合させます。*/ if((strlen(str1) + strlen(str2)) < 80 ){ strcat(str1, str2); printf("%s\n", str1); } /*str2をstr1にコピーする*/ strcpy(str1, str2); printf("%s %s\n", str1, str2);

  • C言語の問題

    選んだファイルのデータを読み取り、そのファイルのデータの中の文字列を数えるプログラム(例えば、「I like sport」 だったら3ワード)を作りたいのですが、文字数を数えるものしかわからないです。 一応、下のプログラムが文字数を数えるものですが、どうすれば文字列を数えるものになりますでしょうか?教えてください。 #include <stdio.h> #include <string.h> #include <stdlib.h> main() { FILE *fin; char filename[20]; char data[256]; int n; printf("ファイル名の入力 :"); gets(filename); fin=fopen(filename,"r"); if(fin == NULL){ printf("%sがオープンできません!\n",filename); exit(1); } while(fgets(data,256,fin) !=NULL){ } n=strlen(data); printf("ファイル %s には、%dワードがあります。\n",filename,n); fclose(fin); }

  • C言語の問題がわかりません。

    C言語の問題がわかりません。 ファイルを読み込んで、文字数と単語数を数えるプログラムなのですが、 例えば、ファイルが 「I was born in Japan  I like baseball」でしたら、 1:I was born in Japan 19文字、5単語 2:I like baseball 15文字、3単語 と表示したいのですが、下記のプログラムのままだと、 1:I was born in Japan 20文字、5単語 2:I like baseball 15文字、3単語 と作った文章の改行の部分を認証してしまいます。 改行の部分を認証しないようにこれを修正するにはどうしたらいいでしょうか? また、もう一つあるのですが、結果の文章を 1:napaJ・・・ 2:・・・ekil I と行ごとに逆に表示したいのですが、どうすれば逆に表示できますでしょうか? #include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { FILE *fin; char filename[20]; char data[256], *abc; int a,b,n; printf("ファイル名の入力 :"); scanf("%s", filename); fin=fopen(filename,"r"); if(fin == NULL){ printf("%sがオープンできません!\n",filename); exit(1); } a=0; b=0; n=0; while(fgets(data,256,fin) != NULL) { a=a+1; b=strlen(data); abc = data; *(abc - 2) = '\t'; while (*abc == ' ') {abc++;} while (*abc != '\0') { while (*abc != '\0' && !(*abc == ' ' || *abc == '\t' || *abc == ',' || *abc == '.')){abc++;} n = n+1; while (*abc != '\0' && (*abc == ' ' || *abc == '\t' || *abc == ',' || *abc == '.')) {abc++;} } printf("%d:%s\n",a,data); printf("%d文字、%d単語\n",b,n); n=0; } fclose(fin); return 0; }

  • C言語の質問です

    下記のプログラムはテキストファイルを読み込み、AからZまでの文字(小文字、大文字は区別しない)がそれぞれ何回 現れたかを数えるプログラムです。 #include <stdio.h> #include <stdlib.h> #include <ctype.h> int count[26]; int main(int argc, char *argv[]) { FILE *fp; char ch; int i; /* ファイル名の指定を調べる */ if(argc!=2) { printf("ファイル名の指定がありません\n"); exit(1); } if((fp = fopen(argv[1], "r"))==NULL) { printf("ファイルを開くことができません\n"); exit(1); } while((ch=fgetc(fp))!=EOF) { ch = toupper(ch); if(ch>='A' && ch<='Z') count[ch-'A']++; } for(i=0; i<26; i++) printf("%c は %d 回出現\n", i+'A', count[i]); fclose(fp); return 0; } 1)int count[26]; で、なぜ26なのかが分かりません。 2)count[ch-'A']++; はどういう動作をするのか詳しく教えてほしいです。 3)よって、for文がどういう動作で表示しているのかが分かりません。 未熟者の私ですが、どなたか教えていただけないでしょうか?

  • C言語の配列の使い方について質問です。

    以下のプログラムを配列を使って見やすくしたいのですが、どのように作ったら良いでしょうか? 宜しくお願いします。 #include<stdio.h> int main(void) { int a, b, c, d, e, f, g, h, i, j, k, l, m ,n, o; /*5段目の処理*/ for(a = 1; a <= 15; a++) { for(b = 1; b <= 15; b++) { if(a == b) continue; for(c = 1; c <= 15; c++) { if(a == c || b == c) continue; for(d = 1; d <= 15; d++) { if(a == d || b == d || c == d) continue; for(e = 1; e <= 15; e++) { if(a == e || b == e || c == e || d == e) continue; // printf("%d %d %d %d %d\n", a, b, c, d, e); ////4段目//// if(a>b){ f=a-b; } else if(a<b){ f=b-a; } if(b>c){ g=b-c; } else if(b<c){ g=c-b; } if(c>d){ h=c-d; } else if(c<d){ h=d-c; } if(d>e){ i=d-e; } else if(e<d){ i=e-d; } // printf(" %d %d %d %d \n", f, g, h, i); /////3段目//// if(f>g){ j=f-g; } else if(f<g){ j=g-f; } if(g>h){ k=g-h; } else if(g<h){ k=h-g; } if(h>i){ l=h-i; } else if(h<i){ l=i-h; } // printf(" %d %d %d \n", j, k, l); /////2段目//// if(j>k){ m=j-k; } else if(j<k){ m=k-j; } if(k>l){ n=k-l; } else if(k<l){ n=l-k; } // printf(" %d %d \n", m, n); /////三段目///// if(m>n){ o=m-n; } else if(m<n){ o=n-m; } // printf(" %d \n", o); if(a != b != c != d != e != f != g != h != i != j != k != l != m != n != o){ printf("%d %d %d %d %d\n", a, b, c, d, e); printf(" %d %d %d %d \n", f, g, h, i); printf(" %d %d %d \n", j, k, l); printf(" %d %d \n", m, n); printf(" %d \n", o); } } } } } } }

  • C言語のプログラム

    以下のプログラムはハッシュテーブルを用いて文字列を探すプログラムなのですが、コンパイル時にセグメントエラーとなってしまいます。プログラム中に誤った箇所があれば教えて頂きたいです。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASHSIZE 10 #define MAX_LEN 64 #define N_WORDS 4 struct list { char word [MAX_LEN]; struct list *next; }; struct list *hash_table[HASHSIZE]; char colors[N_WORDS][MAX_LEN] = {"red", "blue", "green", "yellow"}; void my_strcpy(char* a, const char* b) { int i = 0; while(*b != '\0'){ *(a+i) = *(b+i); i++; } *(a+i) = '\0'; } int hash(char *key) { int hashval = 0; while (*key != '\0') { hashval += *key; key++; } return (hashval % HASHSIZE); } int find_word (char *key) { struct list *p; for (p = hash_table[hash(key)]; p != NULL; p++) if (strcmp(key, p->word) == 0) return 1; return 0; } void init_hash_table() { int i, hashvalue; struct list *p, *q; for (i = 0; i < HASHSIZE; i++) { hash_table[i] = NULL; } for (i = 0; i < N_WORDS; i++) { if ((find_word(colors[i])) == 0){ p = (struct list *)malloc(sizeof(struct list)); my_strcpy(p->word, colors[i]); hashvalue = hash(colors[i]); if (hash_table[hashvalue] = NULL) { hash_table[hashvalue] = p; p->next=NULL; } else { q = hash_table[hashvalue]; while (q->next != NULL) q = q->next; q->next = p; p->next=NULL; } } } } void main(void) { init_hash_table(); printf("result = %d\n", find_word("red")); }