ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

C言語(ソース議論をベースに)コミュの教えてください。

  • mixiチェック
  • このエントリーをはてなブックマークに追加
恥ずかしながら、以下のサンプルを組んだはいいんですけど、このプログラムの意味が分かりません。エラーはゼロです。何ができるのか御指南ください。よろしくお願いします。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLEN 256

void openFile();
void closeFile();
void saveFile();
void listLines();
void gotoLine();
void insertString();
void deleteString();
void showHelp();
void countLines();
void enterFileName();
void clearBuffer();
void enterPosition(int *, int *);

char fname[256] = "";
char (*buf)[MAXLEN] = NULL;
int lines = 0;

/*メニュー*/
main()
{
char cmd[20];

while(1) {
printf("command:");
scanf("%s", cmd);

if(strcmp(cmd, "fopen" ) == 0) openFile();
else if(strcmp(cmd, "fsave" ) == 0) saveFile();
else if(strcmp(cmd, "list" ) == 0) listLines();
else if(strcmp(cmd, "gotoln") == 0) gotoLine();
else if(strcmp(cmd, "inss" ) == 0) insertString();
else if(strcmp(cmd, "dels" ) == 0) deleteString();
else if(strcmp(cmd, "help" ) == 0) showHelp();
else if(strcmp(cmd, "exit") == 0) break;
else printf("%s?\n", cmd);
}
clearBuffer();
}

/*ファイル名の入力*/
void enterFileName()
{
printf("filename:");
scanf("%s", fname);
}

/*ファイルの行数のカウント*/
void countLines()
{
FILE *fp;
char s[MAXLEN];

lines = 0;
fp = fopen(fname, "r");
if(fp == NULL)
return;
while(fgets(s, MAXLEN-1, fp))
lines++;
printf("m = %d\n", lines);

fclose(fp);
}

/*バッファ、ファイル名、行数の初期化*/
void clearBuffer()
{
fname[0] = '\0';
lines = 0;
if(buf)
free(buf);
buf = NULL;
}

/*メモリを確保してファイルを読み込む*/
void openFile()
{
int n = 0;
FILE *fp;
char *myline;

enterFileName();

countLines();

buf = (char (*)[MAXLEN])malloc(sizeof(char) * lines * MAXLEN);
if(!buf)
return;

fp = fopen(fname, "r");
if(fp == NULL) {
clearBuffer();
return;
}
while(fgets(buf[n], MAXLEN-1, fp)){
myline = buf[n];
myline[strlen(myline)-1] = '\0';
n++;
}
fclose(fp);
printf("%d行読み込みました。\n", lines);
}

/*メモリの解放*/
void closeFile()
{
char ans[20] = "";
printf("保存しますか?(y or n):");
scanf("&s", ans);
if(ans[0] == 'y')
saveFile();
clearBuffer();
printf("消去しました。\n");
}

/*ファイルの保存*/
void saveFile()
{
int n;
FILE *fp;

enterFileName();
fp = fopen(fname, "w");
if(fp == NULL)
return;
for(n = 0; n < lines; n++)
fprintf(fp, "%s\n", buf[n]);
fclose(fp);
printf("保存しました。\n");
}

/*全行表示*/
void listLines()
{
int n;
for(n = 0; n < lines; n++)
printf("%04d:%s\n", n, buf[n]);
}

/*指定行の表示*/
void gotoLine()
{
int n;
printf("行番号:");
scanf("%d", &n);
if(0 <= n && n < lines)
printf("%04d:%s\n", n, buf[n]);
}
/*文字位置の入力*/
void enterPosition(int *prow, int *pcol)
{
int row, col, characters;
*prow = *pcol = 0;

printf("行番号:");
scanf("%d", &row);
if(row < 0 || row >= lines)
return;
characters = strlen(buf[row]);

printf("桁番号:");
scanf("%d", &col);
if(col < 0 || col >= characters)
return;

*prow = row;
*pcol = col;
}

/*文字例の挿入*/
void insertString()
{
int row, col; /*行番号・桁番号*/
char insstr[MAXLEN]; /*挿入する文字例*/
char newstr[MAXLEN]; /*挿入後の文字例*/
char *myline; /*注目する行*/

enterPosition(&row, &col);
myline = buf[row];
printf("挿入する文字:");
scanf("%s", insstr);
if(strlen(myline) + strlen(insstr) >= MAXLEN)
return;

sprintf(newstr, "%s%s", insstr, myline + col);
strcpy(myline + col, newstr);
printf("%d行%d文字目に\"%s\"を挿入しました。\n", row, col, insstr);
printf("%04d:%s\n", row, myline);
}

/*文字例の削除*/
void deleteString()
{
int row, col; /*行番号・桁番号*/
int delnum; /*削除する文字数*/
char *myline; /*注目する行*/
int mylength; /*注目する行の長さ*/
int i; /*カウンタ*/

enterPosition(&row, &col);
myline = buf[row];
mylength = strlen(myline);
printf("文字数:");
scanf("%d", &delnum);
if(delnum <= 0 || mylength < col + delnum)
return;

for(i = col; i <= mylength - delnum; i++)
myline[i] = myline[i + delnum];
printf("%d行%d文字目から%d文字を削除しました。\n", row, col, delnum);
printf("%04d:%s\n", row, myline);
}

/*ヘルプの表示*/
void showHelp()
{
printf("COMMAND HELP :\"help\"\n");
printf("LOAD FILE :\"fopen\"\n");
printf("RELEASE BUFFER :\"fclose\"\n");
printf("SAVE FILE :\"fsave\"\n");
printf("SHOW ALL LINES :\"list\"\n");
printf("SHOW SINGLE LINE :\"gotoln\"\n");
printf("INSERT STRING :\"inss\"\n");
printf("DELETE STRING :\"dels\"\n");
}

コメント(17)

簡単なファイル作成プログラムみたいですね。ユーザーにコマンド(命令)を入れるようプロンプトを出し,コマンドの種類によって新たにファイルをオープンしたり,そのファイルの指定された行および列に文字を挿入したり,特定の行を表示したり,いろいろとできるようになっています。
ありがとうございます。

さすがに、勤務中は大きくmixi開けないのでこっそりやります。

今後とも、よろしくお願いします。
少しそれますが
σ( ̄。 ̄) オイラ初心者中の初心者なんで
頭オーバーヒートです(・ω・A;)
確かに、何をしたいのかよくわからない非実用的なサンプルですね:-)
各種標準関数が使われていますのでまずはその使い方を把握するところから理解すると良いかと思います。

printf()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/printf.3.html

scanf()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/scanf.3.html

fopen()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/fopen.3.html

fclose()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/fclose.3.html

fgets()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/fgets.3.html

malloc() free()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/malloc.3.html

strcmp()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strcmp.3.html

strlen()
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strlen.3.html
関数の interface の設計が出来てないのは、その辺りの学習まえのサンプルだと思うことにして、

> while(fgets(s, MAXLEN-1, fp))
> while(fgets(buf[n], MAXLEN-1, fp)){
ここ(MAXLEN-1)は、fgets() の仕様を知らなさそう...

> myline = buf[n];
> myline[strlen(myline)-1] = '\0';
ここは意味がわかりません(自己矛盾)

> if(buf)
>  free(buf);
free() の仕様を知らなさそう

あたりがとりあえず目に付きました。
>>> while(fgets(buf[n], MAXLEN-1, fp)){
>> ここ(MAXLEN-1)は、fgets() の仕様を知らなさそう...

あるいは間違って覚えているかですね(同じことか)。トピ主さんのために書き添えておくと、fgets() は以下のように宣言されており;

fgets(char *buf, int size, FILE *stream);

最大で size - 1 文字を読み込みます。従って MAXLEN - 1 の "-1" は必要ないわけです。

>>> if(buf)
>>>  free(buf);

仕様としては free() に NULL pointer を放りこんでもよいわけですが、NULL だとわかっていればわざわざ free() を呼ばなくてもよいので、if で分岐させるほうが速いコードになるってことはありえますかね?
>仕様としては free() に NULL pointer を放りこんでもよいわけですが、NULL だとわかっていればわざわざ free() を呼ばなくてもよいので、if で分岐させるほうが速いコードになるってことはありえますかね?

free関数内で判断するか、その上で判断するかなので、速くなると思います。
上記サンプルのようにグローバルに変数をもたせ、free後の0初期化を行うとわかっている場合は、なおさらだと思います。
また、頻繁にmalloc・freeをするような場合は、マクロにしたりinlineにするともっと高速になっていいと思います。
>だいはどサン
>Charlieさん
>でめサン

ありがとうございました。
自分も教える側に1日でも早くなれるように、日々精進します。ので、これからもよろしくお願いします。
でめさん,ありがとうございます。(^^)

あっつんさん,私もまだまだ修行中の身です。いっしょに勉強していきましょう。
ちょっと重箱の隅をつつきます^^;
呼び出しにかかわる命令数やcacheのことを言っているのなら確かにそうなのですが、そもそもNULLになる場合の頻度が多いのでしょうか?
ほとんどがNULLではない場合、その無駄なifは問題ではないのでしょうか?
そもそも、free() のコストはそんなレベルではないくらいかかります。
以上、重箱の隅つつきはおわりにします:-)

ともかく、NULLを渡せるという仕様を知っておいて損はないと思います。
上記レスにも書いてありますが、
NULLだとわかっていれば
と言うのが前提です。

Charlieさんがおっしゃるように、NULLの確立が低い場合は、ifを入れる事はないと思います。
>> ともかく、NULLを渡せるという仕様を知っておいて損はない

それにはまったく同感です。(^^)
>5: Charlie さん

>> myline = buf[n];
>> myline[strlen(myline)-1] = '\0';
>ここは意味がわかりません(自己矛盾)

すいません、ここがよくわからないのですけど、
矛盾ということは
>fprintf(fp, "%s\n", buf[n]);
全部こう(直後に改行)するなら削除するなということでしょうか?
Charlie さん、

プヨぷよさんの上記のコードは、おそらくは文字列の最後にあるであろう改行文字を null 文字に置き換える作業をしているのだと思います(fgets は改行文字も保存するので)。

プヨぷよさん、もしそういう意図でないなら訂正していただけるとうれしいです。
あぁ、そういう意味なのね:-)
# 気づかないわたしは間抜けでしたね
それなら、
if ((p = strchr(myline, '\n')) != NULL)
  *p = '\0';
がいいな:-)
>> myline[strlen(myline)-1] = '\0';
は、ファイルの末尾に改行がないとき困るなぁ:p
もちろん、一行に255bytes以上あるときも困る:p
そうですね、そういう類のエラーチェックが抜けているのは確かです。そのへんの細かいところは初心者のうちからしっかり頭に入れておくのがよいですね。(^^)

私も Charlie さんのコードがスマートでよいと思います。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

C言語(ソース議論をベースに) 更新情報

C言語(ソース議論をベースに)のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング