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

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

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

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

Q&A

解決済

1回答

528閲覧

grep関数を実現するソースコード内の、argcとargvの扱い方について教えてください

TeraTera

総合スコア3

C

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

1グッド

0クリップ

投稿2023/02/11 05:35

実現したいこと

オプションを取るgrep関数内の、argcとargvの扱い方について理解する

前提

下記オプションを取れるgrep関数を実現するソースコード上にて、argcとargvを加算、減算するタイミングとその目的が理解できない状態です。

「該当のソースコード」欄に、ソースコードの全文を掲載させて頂きました。
この中で、以下の4行について、なぜargcとargvをここで加算、減算しているのかを教えて頂きたく思います。

/*get_opt関数直後の2文*/ argc -= optind; argv += optind; /*char *pattern = argv[0]を実行した直後の2文*/ argc--; argv++;

get_opt関数直後の2文については、以下のような理解です。

・ argc += optindについて
→grepしたい文字列が引数としてコマンド実行時に与えられているかを判定するため

・argv += optindについて
→grepしたい文字列を*charに格納するため、argvの先頭アドレス + optindバイト分argv[0]のアドレスをずらしている

問題は、char *pattern = argv[0]を実行した直後の2文です。
ここでなぜ、argc --; argv ++;が挟まるのでしょうか?
(この処理を挟むことで、コードが正常に実行されることは分かるのですが、タイミングと目的が分からず)
よろしくお願い致します。

該当のソースコード

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <regex.h> #include <unistd.h> static void grep_file(regex_t *re, char *path); static void grep_stream(regex_t *re, FILE *f); static int opt_invert = 0; static int opt_ignorecase = 0; int main(int argc, char *argv[]) { int opt; while ((opt = getopt(argc, argv, "iv")) != -1) { switch (opt) { case 'i': opt_ignorecase = 1; break; case 'v': opt_invert = 1; break; case '?': fprintf(stderr, "Usage: %s [-iv] [<file>...]\n", argv[0]); exit(1); } } argc -= optind; argv += optind; if (argc < 1) { fputs("no pattern\n", stderr); exit(1); } char *pattern = argv[0]; argc--; argv++; int re_mode = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; if (opt_ignorecase) re_mode |= REG_ICASE; regex_t re; int err = regcomp(&re, pattern, re_mode); if (err != 0) { char buf[1024]; regerror(err, &re, buf, sizeof buf); puts(buf); exit(1); } if (argc == 0) { grep_stream(&re, stdin); } else { int i; for (i = 0; i < argc; i++) { grep_file(&re, argv[i]); } } regfree(&re); exit(0); } static void grep_file(regex_t *re, char *path) { FILE *f; f = fopen(path, "r"); if (!f) { perror(path); exit(1); } grep_stream(re, f); fclose(f); } static void grep_stream(regex_t *re, FILE *f) { char buf[4096]; int matched; while (fgets(buf, sizeof buf, f)) { matched = (regexec(re, buf, 0, NULL, 0) == 0); if (opt_invert) { matched = !matched; } if (matched) { fputs(buf, stdout); } } }
melian😄を押しています

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

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

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

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

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

jimbe

2023/02/11 06:40

>argvの先頭アドレス + optindバイト分argv[0]のアドレスをずらしている 微妙に危なっかしい書き方をされていますが、 argv はポインタ配列ですので、 optind 個のポインタ分 argv をずらしている、です。
TeraTera

2023/02/11 06:51

おお、なるほど。 「optindのポインタ分argvがポインタとして差している先頭アドレスをずらしている」と言い換えた方が正確、ということでしょうか?
jimbe

2023/02/11 08:54

文章で書くと難しい部分ですよね^^;
guest

回答1

0

ベストアンサー

ここでなぜ、argc --; argv ++;が挟まるのでしょうか?

引数のうちのパターンを飛ばして、次の引数であるファイル名にポインターを進めるためです。

argc -= optind;
argv += optind;

で、オプション部分を飛ばしているのと同じ考え。

投稿2023/02/11 05:59

otn

総合スコア84559

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

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

TeraTera

2023/02/11 06:59

なんとなく理解できたかもしれません。。 つまり、argcはファイルを引数として取るかどうかの条件分岐の判定として。 argvはそれが真となる場合における、ファイルを取得するための配列型ポインタとして機能している。 という理解でいいでしょうか?
otn

2023/02/11 08:43

というか、argvは引数を参照する手段であり、処理済みの引数は+1して順次飛ばしていって、 argc は未処理の引数が何個残っているかです。
jimbe

2023/02/11 08:58 編集

main の最後のほうにある (grep 処理としてメインの) if (argc == 0) { grep_stream(&re, stdin); } else { int i; for (i = 0; i < argc; i++) { grep_file(&re, argv[i]); } } を、オプションがあっても無くても動作するように各変数を調整しているですね。
y_waiwai

2023/02/11 09:32

ちと誤解があるかと補足しときます 関数の引数ってのは、引数の値を初期値とした、ただのローカル変数です。 なので、演算もできれば代入もできます。 引数だからと特別な動作はしません
TeraTera

2023/02/13 04:14

皆さんありがとうございます! なるほど!argcはオプション以降の引数が、幾つ残っているかのカウンタとして。 argvは後続にファイルを取る場合の参照手段として使用しているのですね! 理解できました〜! y_waiwaiさんもありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問