質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

895閲覧

C言語 別ファイルを配列に読み込んでコマンドで操作したい

nekoatsume

総合スコア7

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

2クリップ

投稿2020/05/20 15:25

編集2020/05/24 02:22

C言語初心者です。
日本語が記載されている別ファイルを配列に読み込んで、コマンドで操作できるようにしたく
下記のコードを書きました。
現在できているコマンドは下記の通りです。
P :1行前を表示(カーソル移動させる)
N : 1行後を表示(カーソル移動させる)
S : カーソル前後10行を表示(カーソル移動しない)
t : 先頭行へ移動(カーソル移動させる)
l : 最終行を表示(カーソル移動させる)

<実現したいこと>
追加で書きのコマンドを作りたいのですが、うまくいかず困っています。
i :実行画面で文字を入力すると、入力した文字が カーソル行の前に1行挿入される(カーソル移動)
a : カーソル行の後ろに1行挿入(カーソル移動させる)
d : カーソル行を削除したい(カーソルは同じ行に留まる)
r : 実行画面で文字を入力すると、カーソル行を入替えする(カーソルは留まる)
v : 任意のファイル名で保存(オープンしたファイル名がデフォルト)

i,a,dについてはコード書いてみましたが、うまくいきません。
(i,aは文字入力はできるが、2列にわたって文字入力し実行しないと機能していない状態で、
カーソルの移動がうまくいってないようです)
(dについてはアルゴリズム自体違っていると思いますが全く機能していないです)
r,vについては今手付かずになっています。

i,a,dの解決方法について教えていただけたら幸いです。
r,vについても可能であれば実装方法助言いただけないでしょうか。

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <ctype.h> #define GYO 200 //1ファイルの最大行数 #define MOJI 256 //1行の最大文字数 #define LINE line+1 int kansu(char* str,FILE* fp); int main(int argc,char* argv[]) { FILE* fp; char str[GYO][MOJI]; char retsu[128]; int i=0; int line=0;//現在の行番号 int gyo; int k;    if(argc==2){     if((fp=fopen(argv[1],"r"))==NULL){     printf("ファイルが開けませんでした\n");     exit(EXIT_FAILURE);     }    } else{ printf("引数の値が不正です\n"); exit(EXIT_FAILURE); } //strにファイルの内容読込み while(fgets(str[i],MOJI,fp)!=NULL){ //ファイルの行数チェック   if(i>GYO){    printf("ファイルの長さが[%d]を超えました",GYO);    break;   }   if(strlen(str[i])==255){    if(kansu(str[i],fp)){     exit(EXIT_FAILURE);   }     printf("strlen=[%ld]\n",strlen(str[i]));   }     printf("%d:%s",LINE,str[line]);     printf("%ld\n",strlen(str[line]));     line++;     i++;   }    line--;    int line_max=line;//ファイル全体の行数   while(1){ printf("コマンドを入力してください:");     fgets(retsu,sizeof(retsu),stdin);    //大文字も小文字も対応する処理     for(k=0;k<strlen(retsu);k++){     retsu[k]=tolower(retsu[k]);     }     //nコマンドのため     gyo=atoi(retsu);     gyo--; //各コマンドの処理     if(strchr(retsu,'o')){       for(int i=0;i<line_max;i++){     if(i==line){     printf("*%d:%s\n",i+1,str[i]);     }else{     printf("%d:%s\n",i+1,str[i]);       }     }     printf("line:%d\n",LINE);     printf("line_max:%d\n",line_max+1);     }else if(strchr(retsu,'d')){         if(line==0){         strcpy(str[line],"");         printf("配列削除しました\n");     }else if (line_max==line){         strcpy(str[line],"");         line--;         line_max--;     }else{        for(i=line;0<=(line_max-i);i++){        strcpy(str[i],str[i+1]);        }       line_max--;     }        printf("*%d:%s\n",LINE,str[line]);    }else if(strchr(retsu,'r')){        if(line<0){        printf("文字列が入っていません\n");        continue;    }        printf("Enter sentence:");        fgets(str[line],MOJI,stdin);        printf("%d:%s\n",LINE,str[line]);        continue;    }else if(strchr(retsu,'a')){    if(line<0){     printf("文字列が入っていません\n");     continue;    }    for(int i=line_max; i>=line; i--){      strcpy(str[i+1],str[i]);    }      line_max++;      line++;      fgets(str[line],sizeof(str[line]),stdin);      printf("*%d:%s\n",LINE,str[line]);      continue;    }else if(strchr(retsu,'i')){      for(int i=line_max;i>=line;i--){      strcpy(str[i+1],str[i]);    }       line_max++;     fgets(str[line],sizeof(str[line]),stdin);     printf("*%d:%s\n",LINE,str[line]);    }else if(strchr(retsu,'p')){        if(line<1){        printf("ファイルの先頭です\n");        continue;    }        line--;        printf("*%d:%s\n",LINE,str[line]);    }else if(strchr(retsu,'n')){    if(line>line_max){        printf("最端行数を超えました\n");        line=line_max;    }        line++;        printf("*%d:%s\n",LINE,str[line]);        continue;    }else if(strchr(retsu,'s')){     int p=line-10;       if(p<1){        p=1;    }     int n=line+10;     if(n>line_max){     n=line_max;    }    for(i=p;i<=line;i++){       printf("%d:%s\n",i,str[i-1]);    }       printf("*%d:%s\n",LINE,str[line]);    for(i=line+1;i<n+1;i++){       printf("%d:%s\n",i+1,str[i]);    }    continue;    }else if(strchr(retsu,'f')){    int x;    int y;    int z;    /*配列の数値を交換*/    for(x=0;x<line_max-1;x++){      str[line]=x;       for(y=(x+1);y<line_max;y++){        if(str[y]<str[line])line=y;       }    z=str[line];    str[line]=str[x];    str[x]=z;    }    if(line>line_max){    printf("入替えできません\n");    }    printf("%d:%s\n",LINE,str[line]);    continue;   }else if (strchr(retsu, 'v')) {   char fname[128];   char c2[5];   FILE* wfp;   printf("file name is [%s] ?:[y or n]: ", argv[1]);       fgets(c2, sizeof(c2), stdin);   if (strchr(c2, 'y')) {     strcpy(fname, argv[1]);   } else if (strchr(c2, 'n')) {     printf("Enter file name:");   fgets(fname,sizeof(fname),stdin);   } else if(c2[0] == '\n') {     continue;   } else {    printf("Command Error.[%s]\n",c2);    continue;   }   if ((wfp = fopen(fname, "w")) == NULL) {     printf("File open Error:w\n");   }     for (i=0; i <= line_max; i++) {     fprintf(wfp, "%s", str[i]);   }     fclose(wfp);     printf("Write Finish...\n");     continue;   }else if(strchr(retsu,'t')){    line=1;    printf("%d:%s\n",LINE,str[line]);   }else if(strchr(retsu,'l')){   line=line_max;   printf("%d:%s\n",LINE,str[line]);   printf("linemax=%d\n",line_max+1);   }else if(strchr(retsu,'x')){    printf("終了\n");    break;   }else if(gyo<=line_max && gyo>=0){    line=gyo;    printf("*%d:%s\n",LINE,str[line]);    continue;   }else{    printf("retsu:%s\n",retsu);    printf("line:%d\n",line);    printf("コマンドが不正です\n");    continue;   }   }    fclose(fp);    exit(EXIT_SUCCESS);   } ///関数 int kansu (char* str,FILE* fp) { int i=254; int r=0; printf("str[i]==[%d]\n",(unsigned char)str[i]); printf("str[i]==[%c]\n",(unsigned char)str[i]); printf("str[i]==[0x%x]\n",(unsigned char)str[i]);   if((unsigned char)str[i]=='\n' || str[i]=='\0'){      printf("改行、NULLを検知する\n");      return 0;   }   else if((unsigned char)str[i]>=0 && (unsigned char)str[i]<=127){    printf("00〜7Fに入りました\n");    str[i+1]=10;    str[i+2]=0;    return 0;   }        else if((unsigned char)str[i]>=224 && (unsigned char)str[i]<=239){printf("E0〜EFに入りました\n");    str[i]=10;    str[i+1]=0;    r=fseek(fp,sizeof(char)*-1,SEEK_CUR);     if(r){       printf("seekに失敗しました\n");       return -1;    }       return 0;    }    else if((unsigned char)str[i]>=128 &&(unsigned char)str[i]<=191){     printf("80~8Fに入りました\n");       if((unsigned char)str[i-1]>=128 &&(unsigned char)str[i-1]<=191){       str[i+1]=10;       str[i+2]=0;       return 0;   }    else{       str[i-1]=10;       str[i]=0;       return 0;       r=fseek(fp,sizeof(char)*-2,SEEK_CUR);       if(r){            printf("seekに失敗しました\n");            return -1;       }            return 0;     }  } else if((unsigned char)str[i]>=224 && (unsigned char)str[i]<=239){ printf("E0〜EFに入りました\n"); str[i+1]=10; str[i+2]=0; return 0;        } }

作業環境はLinuxのubuntu上です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2020/05/20 19:26

うまくいかないとはどういう動作になるんでしょうか
ttyp03

2020/05/21 02:14

人に見せるんだからインデントくらい綺麗にしましょう。
guest

回答3

0

文字配列の代入(というかコピー)は、前回の回答にあるように「strcpy(str[i], str[i-1])」で行います。
「カーソルの前の行と入替える」の意味が、前の行「DEF」カーソル行「ABC」→前の行「ABC」カーソル行「DEF」となることであれば、forのループは不要で、「str[line-1]」と「str[line]」の入れ替えだけとなります。
宣言を「char z[MOJI]」に変更して、「strcpy(z, str[line]); strcpy(str[line], str[line-1]); strcpy(str[line-1], z);」で入れ替えます。
「f」での範囲チェックは、0より小さい位置を参照しないか、のほうですね。

C

1 char z[MOJI]; 2 if (line-1 < 0) 3 { 4 printf ("入替えできません\n"); 5 continue; 6 } 7 strcpy(z, str[line]); 8 strcpy(str[line], str[line-1]); 9 strcpy(str[line-1], z); 10 printf ("%d:%s\n", LINE, str[line]); 11 continue;

投稿2020/05/24 01:53

etsuhisa

総合スコア416

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

etsuhisa

2020/05/24 01:56

私自身このサイトの経験が浅いので作法がわからないですが、広く回答を集めれたほうがよいと思うので、こういった追加の質問の場合には、別質問にしたほうがよいかもしれません。質問のコードと回答がずれてしまいますし。
nekoatsume

2020/05/24 04:31

ご回答ありがとうございました! 仰る通り、追加の場合は新たに立ち上げた方がよさそうですね^^; ひとまず、fとbは実装できたのでa,iのreallocはチャレンジしてみます。 また追加で質問出てきたら別であげさせていただきます。 毎度ご親切に本当にありがとうございます。
guest

0

ベストアンサー

最初に、カーソル行の扱い方をきれいにする必要があると思いました。
このソースでは、lineがカーソル行を意味していると考えますが、lineがどの位置を指しているかが混乱しやすいと思います。
lineなので1行目からにしたいところですが、ソースコード中のカウンタは常に0始まりで扱ったほうがよく、表示の時だけ「line+1」で行番号として表示するとよいです。

0始まりにします。

C

1 int line=0;//現在の行番号

表示の時はline+1で出力します。

C

1 printf("%d:%s",line+1,str[i]);

line_maxは行数なのでループ後のlineの値です。
カーソルが最後の行+1の位置になっているので、1つ前の行にします。

C

1 int line_max=line;//ファイル全体の行数 2 line--;

「p」コマンドから手を付けます。
lineは0始まりにしたので、「line<1」は正しい判定です。
表示は「line+1」とします。

C

1 }else if(strchr(retsu,'p')){ 2 if(line<1){ 3 printf("ファイルの先頭です\n"); 4 continue; 5 } 6 line--; 7 printf("*%d:%s\n",line+1,str[line]);

次に、質問にあったコマンドのうち「i」の実装です。
挿入なので、最初に挿入する場所を空けなければなりません。
最後の行から1行ずつ後ろにコピーしていきます。
空いた場所に、fgetsで改行のある文字列を読み込みます。
scanfだと空白や改行を扱えないのでfgetsにします。
挿入後のカーソルの位置は、今入力した行が表示されたほうが自然だと感じました。

C

1 }else if(strchr(retsu,'i')){ 2 //lineの位置に空きを作るため、1つずつ後ろにずらす 3 //後ろからコピーしないと上書きしてしまう 4 for(int i=line_max; i>=line+1;i--){ 5 strcpy(str[i], str[i-1]); 6 } 7 line_max++; //挿入して1行増えたので 8 fgets(str[line], sizeof(str[line]), stdin); 9 //line++; カーソルを移動しないほうが自然 10 printf("*%d:%s\n",line+1,str[line]);

これらを参考に、まず移動系のコマンドのlineの整理をするとよいです。
0始まりにしたことで、常にstr[line]で考えることができます。

「a」と「d」は「i」の応用です。
「a」はline++をしてから「i」の処理を行えばよいです。
「d」は「i」の空きを作る処理と反対で、1つ前の行にコピーしていき、line_maxをデクリメントします。

投稿2020/05/21 11:52

etsuhisa

総合スコア416

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nekoatsume

2020/05/23 16:18

ご丁寧に教えていただき本当にありがとうございました。 無事、a,i,v,rの機能を実装することができました!(表示する方をLINEで定義し整理してみました) そして、今週末の課題で追加で相談させていただきたく、、 下記の機能を追加したいです。 「b」…カーソルの後ろの行と入替える(カーソルは元のカーソル行)     ※入替えできない場合はその旨表示 「f」…カーソルの前の行と入替える(カーソルは元のカーソル行)  ※入替えできない場合はその旨表示 まずfのコードを書いてみたのですが、z=str[line]; str[line]=str[x]; str[x]=z;のところでassignment to expression with array typeとエラーがでてしまいうまくいきません。 また、実装したa,iのコマンドについてはreallocを使って行を増やす、 dコマンドではreallocを使って行を減らすという仕組みに変えたいのですがaの場合で fgetを使用しているところをline=realloc(line,sizeof(int))のように書き換えるということに なりますでしょうか・・? お忙しいところ恐縮ですが、ご協力いただけましたら幸いです。何卒よろしくお願いいたします。
etsuhisa

2020/05/24 02:35

fについては回答に書きました。dのreallocについてはchar str[GYO][MOJI]の宣言から変更し、mallocで確保しないとならないです。
guest

0

}else if(strchr(retsu,'d')){

str[line]==NULL; printf("*%d:%s\n",line,str[line]);

== というのは比較です
ここでなにをしてるのか説明できるでしょうか

投稿2020/05/20 19:53

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問