• 締切済み

配列オーバーフロー?

文字列を(順番を変えて)コピーして表示させるプログラムを 作っていますが、うまく表示されずに困っています。 具体的にお話しますと・・・ 「abc・・・xyz」→「zyx・・・cba」等としたり、色々 文字列の順序を変えた内容を表示するのでこの部分は問題ないと思ってます。 こうしたプログラムで文字列のchar配列を200程度にして、 1行あたり50文字程度で数行程度ならちゃんと表示されるのですが これを数十行で行うと部分的に化けるところが出てきます。 わかる人にアドバイスを貰ったところ配列オーバーフローではないか? と言われましたがそれ以上の情報は得られず、 何が問題なのがよくわからず困っております。 ・文字列は一文字ずつ配列を用いている ・文字のコピーはstrcpyを用いている →for(i=0,j=0;i<MAX;i++) strcpy(&moji[i],&mojimoji[i]); ・strncpyを用いると「フ」というのが交じってくるので使っていない ・初期化はこんな感じで行っている →for(i=0;i<MAX;i++) strcpy(&moji[i],"\0"); 何よりよくわからないのが、同じような内容の行でも 化ける行と化けない行があり、化けるというのはその行にない文字が 入ってきてしまうというものです。

みんなの回答

回答No.10

> enc_dec()の先頭にあるこの行は、何をしたいのでしょうか。  消し忘れです。  

全文を見る
すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.9

>#8さん > if(!buf) return 0; enc_dec()の先頭にあるこの行は、何をしたいのでしょうか。 buf が NULL だったら return 0 するって、当該関数で buf[] を定義しているんだから NULL になるわけがないですよね。

全文を見る
すると、全ての回答が全文表示されます。
回答No.8

#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 200 int enc_dec(char *s, int n, int m, int x) { char buf[MAX]; int i, j, k; if(!buf) return 0; if(x){ for(k = i = 0; i < m; i ++){ for(j = 0; i + m * j < n; ++ j) buf[k ++] = s[i + m * j]; } } else{ for(k = i = 0; i < m; i ++){ for(j = 0; i + m * j < n; ++ j) buf[i + m * j] = s[k ++]; } } buf[k] = '\0'; strcpy(s, buf); return 1; } int main(int argc, char *argv[]) { FILE *fp1, *fp2; char s[MAX], *c; int x; if(argc != 4) exit(1); if(!(fp1 = fopen(argv[1], "r")) || !(fp2 = fopen(argv[2], "w"))) exit(1); x = atoi(argv[3]); while(fgets(s, MAX, fp1)){ if(c = strchr(s, '\n')) *c = '\0'; enc_dec(s, strlen(s), 4, x); fprintf(fp2, "%s\n", s); puts(s); } fclose(fp1); fclose(fp2); return 0; }

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.7

あー、そーゆー仕様な訳ですか。なら配列宣言は問題ないですね。 -- // 暗号化--ここから----4行化 for(i=0,m=0;m<((len/GYOU)+1);m++){ for(n=0;n<GYOU;n++,i++){ strcpy(&code_on[m][n],&moji_before[i]); if(len==i+1){ n=GYOU; m=CODE_MAX; } } } // ----1行化 for(i=0,n=0;n<(GYOU+1);n++){ for(m=0;m<((len/GYOU)+1);m++){ if(strcmp(&code_on[m][n],"\n")!=0){ strcpy(&moji_after[i],&code_on[m][n]); i++; } -- 4行化については#6でも触れましたが、 -- i = 0; for(n=0; len <= (n + 1) * GYOU; n++){ strncpy(&code_on[n][0],&moji_before[n * GYOU]); code_on[n][GYOU] = '\0'; } -- の方がスマートですね。 #つーか#6のコードちょっとバグってるよ>俺orz 1行化の方ですが、#6でも言った通り「1文字ずつの抽出なら代入を使いましょう」。比較も同様です。 ついでにちとスマート化にチャレンジ。 -- i = 0; for(n = 0; n < GYOU; n ++){ for(m = 0; m < CODE_MAX; m ++){ if(code_on[m][n] != '\0' && code_on[m][n] != '\n'){ // ちゃんと初期化されていれば余計な文字は入らない moji_after[i] = code_on[m][n]; i ++; }else{ // 何もしない } } moji_after[i] = '\0'; } --

hardtechno
質問者

お礼

すいません スマートなコードにすることでバグが減るというのはわかりますが 根本的な解決には至っておりません

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.6

もう二つばかり気づいたので。 -- char code_on[CODE_MAX][GYOU_IN]; // 4行時の配列 -- これだと長さGYOU_IN(5)、CODE_MAX(51)行の配列、となってしまいます。 正しくは長さCODE_MAX、GYOU_IN行の配列なので char code_on[GYOU_IN][CODE_MAX]; でなければなりません。 それに合わせて各所の配列の添え字の変更が必要です。 -- // 4行化処理のところ for(i=0,m=0;m<((len/GYOU)+1);m++){ for(n=0;n<GYOU;n++,i++){ strcpy(&code_on[m][n],&moji_before[i]); if(len==i+1){ n=GYOU; m=CODE_MAX; } } } -- > strcpy(&code_on[m][n],&moji_before[i]); はstrlen(&moji_before[i])が5-nを超えた場合、code_on[m][n]からcode_on[m][GYOU_IN]に収まりきらず以降のエリアも上書きされます(配列オーバーフロー)。 #上の指摘前なのでそうなります。上記のように書き換えたら50-nになります メモリ配置上は次の行の先頭につながっている訳ですが(だから書き換わってしまう)、4行目を書いたあとは未知のエリアに書き込んでいることになるため非常に危険です。 というか#5を書いてる最中にも思ったのですがstrcpy()は「1文字をコピーする関数」ではないということです。そういう目的なら関数なぞ使わず素直に代入を使いましょう。 #どう見ても使い方がそうなってるので一応念押ししておきます 行あたり何文字をコピーすればいいのかを管理して、strncpy()もしくはmemcpy()を使うべきです。 -- たとえば i = 0; cpy_len = (len / GYOU) + 1; for(n=0;n<GYOU;n++){ strncpy(&code_on[n][0],&moji_before[n * cpy_len]); code_on[n][n * cpy_len] = '\0'; } --

hardtechno
質問者

補足

最初のだけ。 4行って言い方がまずかったのだとおもいますが、 ABCD EFGH IJKL MN ・ ・ ・ と4文字ずつ↓に伸びていくのでそのままでよいんじゃないですか?

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.5

-- for(i=0,m=0;i<MAX_IN;m++){ strcpy(&filename_before[i],"\0"); strcpy(&filename_after[i],"\0"); for(n=0;n<GYOU;n++){ strcpy(&code_on[m][n],"\0"); i++; } if(i!=MAX_IN){ strcpy(&moji_before[i],"\0"); strcpy(&moji_after[i],"\0"); strcpy(&moji_dummy[i],"\0"); } } -- なして配列の0初期化がこんなややこしいコードになるんだろう…… memset()はご存じないですか? あと、nをカウンタとしたforループの中でiをインクリメントしてる関係で filename_before,filename_after,moji_before,moji_after,moji_dummyの配列はGYOU(4)間隔でしか0が入りません(初期化漏れ) これが原因じゃないですか?

hardtechno
質問者

お礼

moji_dummyがおかしいっぽいのですがはじめのwhileで初期化してますし・・う~ん・・解決していません。

hardtechno
質問者

補足

なにぶん初心者なものでよくわかっていませんです。 初期化漏れですか・・試してみます。

全文を見る
すると、全ての回答が全文表示されます。
noname#198419
noname#198419
回答No.4

char moji[MAX]; とかで配列の型を宣言してあるならば、「配列の添え字は0からMAX-1までで、MAX個の配列になる」ということが教科書に書いてあるはずです。 for(i=0,j=0;i<MAX;i++)などで、式の評価の順番を教科書などで確認して、forの挙動を観察するための簡単なコードを書いて実験してみると、理解しやすいと思います。 あと、文字列の終わりは'\0'になっているひつようがあることも教科書に書いてあるはずです。

hardtechno
質問者

補足

MAX+1にする形にしています。 初めに\0で初期化しています。 全部ではなく、一部分だけが化ける事を不思議に思っています。

全文を見る
すると、全ての回答が全文表示されます。
  • arain
  • ベストアンサー率27% (292/1049)
回答No.3

No.2です。 とりあえずソースは軽く確認しました。 そこで質問です。 >C言語の初歩の本読んだくらいの知識であれば・・ >ただ、そこから中級者向けとなると理解していないと思います。 Q1.「文字列」の定義を説明してください。 Q2.memcpy()等、mem***()となる関数は知っていますか?

hardtechno
質問者

補足

Q1.アスキーコードで表わされる文字が連なるもの、最後に\0がつく Q2.memmoveは使った事がありますが、これでも「フ」が出ました。 また、具体的な事はよくわかっていません。 この程度ですかね

全文を見る
すると、全ての回答が全文表示されます。
  • arain
  • ベストアンサー率27% (292/1049)
回答No.2

全部のソース公開してください。 >・strncpyを用いると「フ」というのが交じってくるので使っていない から、確実に配列の定義や使用方法、str系の関数の使い方が間違っていることはわかりますが、それ以上のことはわかりません。 ちなみに、C言語の「文字列の定義」って理解されてます?

hardtechno
質問者

お礼

#1さんへのコメント追記です。 全て半角文字です。OSはVISTA、Visual C++6.0用いてます。

hardtechno
質問者

補足

C言語の初歩の本読んだくらいの知識であれば・・ ただ、そこから中級者向けとなると理解していないと思います。

全文を見る
すると、全ての回答が全文表示されます。
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.1

まず、ソースを提示して下さい。それと文字列中に漢字(2バイトの文字)は、ないですよね。あと、コンパイラ&OSも提示されていると、良いでしょう。

hardtechno
質問者

お礼

// dummyに一時保存 for(i=0;i<len_sub;i++) strcpy(&moji_dummy[i],&moji_after[i]); for(i=0,j=0;i<len;i++){ if(strcmp(&moji_after[i],"\0")==0){ j++; } strcpy(&moji_after[i],&moji_dummy[i+j]); } strcpy(&moji_after[i],"\n"); if(fputs(moji_after, fp_after)==EOF){ printf("書き込み失敗\n"); return -1; } } fclose(fp_after); fclose(fp_before); return 0; } やっていることは、 ファイルopen→(1行分の文字列read→暗号化→ファイルにwrite)繰り返し→ファイルcloseのつもりです。 ここでいう暗号化とは「abcdefghijklmn」を以下のように4行に分けて abcd efgh ijkl mn 横読みだったものを縦読みにし、「aeimbfjncgkdhl」とします。 どうぞよろしくおねがいします。

hardtechno
質問者

補足

#include<stdio.h> #include<string.h> #define MAX 200 // 1行最大文字数 #define MAX_IN MAX+1 // 1行最大文字数+\0 #define GYOU 4 // 暗号途中処理の1列4文字まで #define GYOU_IN GYOU+1 // 暗号途中処理の1列4文字まで+\0 #define CODE_MAX MAX/GYOU+1 // 暗号途中処理の1行の最大長+\0 int angou(void); int kaidoku(void); /* 未作成 */ int main(){ int ret=1; ret=angou(); return ret; } /******************** 暗号化 ********************/ int angou(){ int i,j,m,n,len,len_sub; FILE *fp_before; // 前ファイルポインタ FILE *fp_after; // 後ファイルポインタ char filename_before[MAX]; // 前ファイル名 char filename_after[MAX]; // 後ファイル名 char moji_before[MAX_IN]; // 前文字列 char moji_after[MAX_IN]; // 後文字列 char moji_dummy[MAX_IN]; // 文字列交換用 char code_on[CODE_MAX][GYOU_IN]; // 4行時の配列 char *fg; // fgets用戻り値 /***** 初期化処理 *****/ for(i=0,m=0;i<MAX_IN;m++){ strcpy(&filename_before[i],"\0"); strcpy(&filename_after[i],"\0"); for(n=0;n<GYOU;n++){ strcpy(&code_on[m][n],"\0"); i++; } if(i!=MAX_IN){ strcpy(&moji_before[i],"\0"); strcpy(&moji_after[i],"\0"); strcpy(&moji_dummy[i],"\0"); } } /***** 暗号化前ファイル名入力 *****/ printf("\n@@@@@暗号化前ファイル名入力\n"); scanf("%s",&filename_before); // 暗号化前ファイルオープン if((fp_before=fopen(filename_before,"r"))==NULL){ printf("ファイルがありません\n"); return -1; } /***** 暗号化後ファイル名入力 *****/ printf("\n@@@@@暗号化後ファイル名入力\n"); scanf("%s",&filename_after); // 暗号化後ファイルオープン if((fp_after=fopen(filename_after,"r"))!=NULL){ printf("同名のファイルが既にあります\n"); return -1; } fp_after=fopen(filename_after,"w"); /***** ファイルから全文取り出す *****/ while(1){ for(i=0;i<MAX_IN;i++){ strcpy(&moji_before[i],"\0"); strcpy(&moji_after[i],"\0"); strcpy(&moji_dummy[i],"\0"); } fg=fgets(moji_before,MAX_IN,fp_before); if(fg==NULL){ break; } len=strlen(moji_before)-1; if(len%GYOU!=0){ len_sub=len+(GYOU-len%GYOU); } else len_sub=len; // 暗号化--ここから----4行化 for(i=0,m=0;m<((len/GYOU)+1);m++){ for(n=0;n<GYOU;n++,i++){ strcpy(&code_on[m][n],&moji_before[i]); if(len==i+1){ n=GYOU; m=CODE_MAX; } } } // ----1行化 for(i=0,n=0;n<(GYOU+1);n++){ for(m=0;m<((len/GYOU)+1);m++){ if(strcmp(&code_on[m][n],"\n")!=0){ strcpy(&moji_after[i],&code_on[m][n]); i++; } } if(len==i+1){ // strcpy(&moji_after[i],"\n"); n=GYOU; m=CODE_MAX; } } // 暗号化--ここまで--------------------------------------

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 2次元配列への標準入力

    初めまして。 私は今C言語のプログラミングを勉強しています。 2次元配列へ文字列の標準入力を行い、それをプリントさせるという問題を考えています。(配列の行の要素はMAXに達しなくても空行が入力されたら 終了させたい。) 下のようなプログラムを書きましたが、空行を入力してプリントする際に 文字が崩れてしまって上手く表示されませんでした。 初歩的で恐縮ですが、どのように改善したら良いか、 教えて頂けたら嬉しいです。 #include <stdio.h> #include <ctype.h> #define MAX 10 int main(){ char array[MAX][MAX]; int i; for(i = 0; i < 10; i++){ fgets(array[i],sizeof(char)*MAX,stdin); if(array[i][0] == '\n') break; } for(i = 0; i < 10; i++){ printf("%s", array[i]); } return 0; }

  • 文字列ポインタの配列の扱い方

    毎度お世話になります。 構造体のメンバが、文字列ポインタの配列だった場合、それに文字列をコピーすることは可能なのでしょうか? とりあえず下記のように書いてみたのですが、実行エラーで終了してしまいます。 typedef struct data{ char name[30]; int age; char *ss[2]; }DATA; int main() { DATA dt[3] = {{"AA",10}, //ssも初期化出来るのか? {"BB",15}, {"CC",20}}; int i,j; for(i=0;i<3;i++){ for(j=0;j<2;j++) strcpy(dt[i].ss[j],"なし"); //それとも、ここでstrcpyで文字列を入れるのか? } よろしくお願いします。

  • 別次元配列への文字コピー

    別次元配列への文字コピー(not文字列)をする際特別な制約ってありますか? 2次元配列から1次元配列への文字コピー 1次元配列から2次元配列への文字コピー などなど for(i=0,n=0;n<TEISU1;n++){ for(m=0;m<TEISU2;m++,i++){ strcpy(&ABC[m][n],&DEF[i]); printf(" i%d n%d m%d %c %x\n",i,n,m,ABC[m][n],DEF[m][n]); // ★★★★★↑この時点では正しく出ているが } } /**/printf("%s\n",ABC); // ★★★★★↑この時点では出力内容がおかしくなっている 原因がさっぱりわかりません。 原因はどういった事が考えられますか?

  • 配列のことでなのですが

    配列で先頭から順番に文字列を格納していきたいのですがどのような方法があるでしょうか? ただforループなどで順番に繰り返すのではなくて、文字列を入力する度に配列の最後尾に文字列を格納していきたいのですが、 例えば for(i=0;i<=10;i++){ scanf("%s",hairetu[i]) } のような方法ではなく配列の中に文字列を前から順番に格納したいです。 詳しい方は知識をかしていただけるとありがたいです。

  • 2次元配列の宣言について

    文字列の配列の場合 Dim m As Variant Dim moji As String m=Array("aa","bb","cc","dd",・・・) moji=m(1) とすれば"bb"がmojiに代入されるのはわかるのですが これを二次元配列(3行4列)にする場合どのように 宣言(Dim~や、Array~)等はどのように記述すればよろしいですか? 基本的な質問でごめんなさい。 よろしくお願いします。

  • ファイル内の文字を配列に格納

    ファイル内の文字列をも表示させた上で、文字列を配列に1つずつ格納したいのですが、とっても簡単な方法で教えてください。 ファイル名は「abc」で配列名は「moji」でお願いします。

  • 文字列を格納する配列を、動的なメモリ確保で処理したい

    文字数が一定でない文字列の一覧を、配列に格納したいと思っています。 "AAA" "BBBBB" "CC" このような文字列を配列に格納するのに普通にやるなら char test[3][24]; for(i=0;i<3;i++){ strcpy(test[i],file[i]); } (便宜上、file[0]には、"AAA",file[1]には"BBBBB"が格納されてるとします) こうやると、test[3][24]の24バイトとか余計に確保した分が無駄になるので、 必要な文字列の長さだけ配列を確保したいと考えています。 で、 char *test[3]; for(i=0;i<3;i++){ //sizeには、各文字列のサイズが格納してあります。ここではその部分省略しますが test[i]= (char*)malloc(size); strcpy(test[i],file[i]); } とやれば (イメージで) test[0]= "AAA" test[1]= "BBBBB" test[2]= "CC" となると思ったのですが、うまく処理されませんでした。 このような処理をさせたい場合根本的に違うのでしょうか。 わかりにくい説明ですが、どなたかご存知の方よろしくお願いします

  • 配列とポインタを使って特定の文字だけ大文字にする

    配列とポインタを使って特定の文字だけ大文字にするプログラムを作りたいのですがどのように作ればいいのでしょうか? 例えば、sportsのsだけ判別してSportSというふうにしたいです。 一応以下のようなプログラムを作ったのですが、実行してもsportsのままで何も変わりません・・・。 #include<stdio.h> void mojihenkan(char *); main(void) { char moji[8]={"sports"}; char *p; int i; mojihenkan(moji); p=moji; for(i=0;i<8;i++){ printf("%c",*(p+i)); } return 0; } void mojihenkan(char *a) { int i; for(i=0;i<8;i++){ if(*(a+i)=='s'){ a-32; } } }

  • 二次元配列のサイズについて

    下記のプログラムにおいて、 Public 文字列格納(,) as Variant とか、 Public 文字列格納(,3) as Variant のような、二次元配列を宣言はできないでしょうか? 下記のプログラムは、A1セルに書かれた文字列を、 一文字ずつに分解してB列に転記し、 逆さにしたものを、1文字ずつにC列に転記する プログラムです。A1セルに書かれる文字列の長さは不定です。 本当の目的は、NCBI等から取得したDNAの塩基配列を入力したら、 相補鎖の塩基配列を作成したり、タンパク質に翻訳したり、 乖離エネルギーを計算したりするためのコードで、その一部を 簡単化したものです。 ===プログラムのソース=== Public 文字列格納 As Variant Public 文字列(100, 2) As Variant Sub テスト() 文字列格納 = Cells(1, 1) 長さ = Len(文字列格納) For i = 1 To 長さ 文字列(i, 1) = Mid(文字列格納, i, 1) 文字列(i, 2) = Mid(文字列格納, 長さ - i + 1, 1) Cells(i, 2) = 文字列(i, 1) Cells(i, 3) = 文字列(i, 2) Next i End Sub

  • 文字列の動的確保とポインタ配列について

    C言語についての質問です。 現在、キーボードから文字列を読み込みファイルに保存するプログラムを作成しています。 プログラムの条件は、以下の通りです。 1: キーボードから英数字(最長でMAX_LEN(1000)-1文字)を入力して文字列(文字配列)dataに格納後、画面に表示する。 2: 入力された文字列と同じ長さの文字列を格納する領域を動的に確保し、文字列dataをその領域に コピーする。なお、必要な文字配列の長さは文字列の長さ+1バイトである。 3: 文字列endが入力されるか、入力された文字列がNUM_STRING(10)個になるまで1~2の処理を繰り返す 4: 各文字列へのポインタを格納する(char *)型ポインタの配列str_p(サイズ:NUM_STRING)を定義して利用する。 5:1~2の処理が終了した後で、メモリに格納されたすべての文字列をファイルに出力する。ファイル名はoutput.txtとし、最初の行に文字列の個数を、次の行以降に入力された順番と「逆の順番」で文字 列を出力すること。 実行例 input ->st22 st22 input->st1 st1 end ファイルの中身 2 st1 st22 現在完成しているプログラムは以下の通りです。 #include<stdio.h> #include<string.h> #include <stdilb.h> #define NUM_STRING 10 #define MAX_LEN 1000 int main (void) { int n, i; char data[MAX_LEN] = {}; char *str_p[NUM_STRING]; FILE *fp; do { printf("input->"); scanf("%s", data); if (strcmp(data, "end") == 0) { break; } else { printf("%s\n", data); n++ 2の処理 } while(n <= NUM_STRING); if ((fp = fopen("output.txt", "w")) == NULL) { fprintf(stdout, "File open error\n"); } fprintf(fp, "%d\n", n); for (i = n-1; i>0; i--) fprintf(fp, "5s\n", str_p[i]); fclose (fp); return 0; } 特に動的確保のところがよく分かりません。 回答よろしくお願いします。       

このQ&Aのポイント
  • 受信はできるが、MFC-L2730で送信できず、ダイヤル音は鳴るが相手が話し中のまま
  • Windows10を使用し、電話回線経由で接続している
  • ひかり回線を使っているが、送信時に問題が発生
回答を見る