• ベストアンサー

この(C言語)ダブルポインタのアルゴリズムを教えて!

main(int argc, char *argv[]) while(--argc > 0) { if(**(++agv) == '-') { switch(argv[0][1]){ case 'a'; オプションaに対する処理; break; case 'b'; オプションbに対する処理; break; case 'c'; オプションcに対する処理; break; default;; abc 以外のオプションが入力された時の処理; } } else break; } オプション以外のパラメータが入力されたときの処理; 特に ’**’の部分や argv[0][1]の意味が解かりません。 よろしくお願い致します。

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

ポインタに*を付けたら、そのポインタが示す先のものになるのは、おわかりですか?(ポインタ操作の基本です) ポインタPが示す先がポインタなら、 *pはポインタになります。 **pは *(*p)、つまり ポインタ*pの示す先、ということになります。 また、 *p = p[0] , *(p+1) = p[1] という、ポインタは1次元配列のようになるのもおわかりですね?(これもポインタ操作の基本) 同様に、**p → *(p[0]) → p[0][0] となります。 あるいは **p → (*p)[0] → p[0][0] となります。 ポインタへのポインタは二次元配列のように扱えます。 > main(int argc, char *argv[]) のように書くと、コマンドライン引数に関する情報がargc,argvに入ります。 第1引数argcは引数の数です。コマンドだけなら1、引数が一つ付くと2,以下3,4,..となります。 第2引数argvは 引数の文字列の列です。 argv[0] に実行ファイルそのものを表す文字列 argv[1] に最初の引数、以下argv[2]...と続きます。 また、文字列なので、charの配列として扱えます。 argv[0][0]は コマンドの最初の文字になります。 > if(**(++argv) == '-') { ここでは、まず、argvを一つ増やします。それにより、いままでargv[0]を指していたポインタ変数argvが、元のargv[1]つまり第1引数の文字列を指すようになります。 そこで、**argv →argv[0][0]です。文字列argv[0]の1文字目です。元のargv[1]つまり第1引数の文字列の1文字目です。 >switch(argv[0][1]){ 上と同様に、文字列argv[0]の2文字目です。元のargv[1]つまり第1引数の文字列の2文字目です。 これをargc回ずらしてループします。

good_play6
質問者

お礼

すごく丁寧な解答を、ありがとうございます。 勉強になりました。

その他の回答 (3)

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.4

みなさんからの回答をもとに図化してみると、 理解度が増すかもしれません。

good_play6
質問者

お礼

御指導ありがとうございます。 勉強になります。

noname#111181
noname#111181
回答No.2

まず **(++argv) ですが、文字列配列 argv が現在指している位置の次の文字列の先頭文字をポイントします。実際には、複数あるコマンドラインオプションの先頭が '-' であるかどうかを調べる if 文です。 次に argv[0][1] ですが、配列 argv の現在指している位置の先頭から2番目の文字をポイントします。実際には、コマンドラインオプションの '-' の次の文字をポイントしています。

good_play6
質問者

お礼

アルゴリズムまで説明していただき、ありがとうございます。 誠にありがとうございました。

回答No.1

main関数の引数のargvは char *argv[] と宣言されています。 これは、argvはchar *、すなわちchar型へのポインタの配列ということです。 また、配列の名前だけ取り出したものは、配列の先頭へのポインタとなるので、argvは「char型へのポインタ」へのポインタとして働きます。 したがって *argvは「char型へのポインタ」を示し、**argvはその「char型へのポインタ」が指すchar型のデータを指すことになります。 同様に、ポインタは配列の先頭として働くので、argv[n]のように添字を付けることで配列のようにデータを扱えます。 したがって、argv[m][n]は、m番目の「char型へのポインタ」の指す領域のn番目のchar型データということになります。 ここではargvはコマンドライン文字列を指してるので、実際にはmは0以外の値にはならないはずですが、これと同じような形で2次元配列を表すことが出来ます。 argv[0][n]は、(*argv)[n]と同義です。

good_play6
質問者

お礼

ポインタと配列の関係について、ありがとうございます。 丁寧な御教授ありがとうございました。

関連するQ&A

  • コンパイルするとエラーに。C言語

    OSはLINUXです。GNOME 端末を使用してます。ここの関数でエラーが起きているみたいなんです。(部分的に載せてしまいましたが、それとも全体も載せた方がいいでしょうか?) void readargs(int argc, char *argv[]) { int c; int atoi(char *); while (--argc > 0 && (c = (*++argv)[0] == '-' || c == '+') { if (c == '-' && !isdigit(*(argv[0]+1))) while (c = *++argv[0]) switch (c) { case 'd': option |= DIR; break; case 'f': option |= FOLD; break; case 'n': option |= NUMERIC; break; case 'r': option |= DECR; break; default: printf("sort: illegal option %c\n", c); error("Usage: sort -dfnr [+pos1] [-pos2]"); break; } else if (c == '-') pos2 = atoi(argv[0]+1); else if ((pos1 = atoi(argv[0]+1)) < 0) error("Usage: sort -dfnr [+pos1] [-pos2]"); } if (argc || pos1 > pos2) error("Usage: sort -dfnr [+pos1] [-pos2]"); } } ちなみに、エラー内容は「case label not within a switch statement」 「break statement not within loop or switch」です。 似たような問題はできたのですが、これだけはなぜかエラーが起きてしまいました。アドバイス・回答待ってます。

  • C言語の変数について

    C言語の変数について教えていただきたいです。 C言語で下記のような設定をした場合、変数A、Bに設定する値にはバイト数制限 はないのでしょうか? バイト数制限がなくなる場合、なぜそうなるのかを教えていただきたいです。 よろしくお願いします。 #include <stdio.h> void test( char **B); int main( int argc, char *argv[] ) { char *A = NULL; char *B = NULL; A = argv[1]; test( B ); return 0; } void test( char **B ) { strcpy(B, "ABCD"); return 0; }

  • C言語のプログラム(ポインタについて)

    /* コマンドライン引数で与えられた長い文字列を長さ10文字ずつに分割してp[100][11]に順番に入れ,表示するプログラム <例>./a.out 1234567890ABCDEFG p[1] = "1234567890" p[2] = "ABCDEFG" */ #include <stdio.h> int main(int argc, char **argv) { int i, len; char *str; len=0; for(i=1; i<argc; i++){ len += strlen(argv[i]); } if((str=(char *) malloc(len+1))==NULL){ perror("malloc"); exit(1); } strncpy(str,argv[1],10); for(i=2; i<argc; i++){ strcat(str,argv[i]); } printf("p[%d] = %s\n", i-1, str); } 上に示した処理をするプログラムを作成したいのですが、 今のソースは単に10文字表示するだけで、ここからどうしたらいいのか見当がつきません・・・・・。 なのでどういった改良をすればよいのか教えていただければ助かります。 /*配列aにファイルから値を読み込み、それを表示した後*/ /*配列に格納された値を下に1つずつずらして表示するプログラム(ポインタを使用して)を作成*/ /*(なお、一番上a[0]にはa[99]の値を入れる)*/ /*<例>*/ /*a[0] = 0 */ /*a[1] = 1 */ /*  ・ */ /*  ・ */ /*a[98] = 98*/ /*a[99] = 99*/ /*a[0] = 99 */ 1つずらしたもの /*a[1] = 0 */ /*  ・ */ /*  ・ */ /*a[98] = 97*/ /*a[99] = 98*/ (読み込むファイル[file-100.dat]には0~99の数字が1つずつ改行しながら入っています) できればこちらにも答えていただければ嬉しいです。 この問のソースは書きませんが、ファイルを配列に読み込んで表示してからの処理がいまいちわからず困っています。 すばやい御回答お待ちしております。よろしくお願いします。

  • C言語のシェルプログラミングの課題が分かりません。

    C言語のシェルプログラミングを作れという課題で、以下のように作ったんですが、実行して何度かコマンドを入力した後、exitによって一発で終わらせることができません。どのように書き換えればいいか教えて下さい。 また、他にも書き換えた方がよいと思えるところがあったら是非教えて下さいm(_ _)m #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include MAX_ARGS 10 #include MAX_LEN 100 extern char **environ; void child(int argc, char *argv[MAX_ARGS]); int main(void){ int argc, n = 0; int status; char input[MAX_LEN], *argv[MAX_ARGS], *cp; const char *delim = "\t\n"; while (1){ ++n; printf("$ "); fflush(stdout); if(fgets(input, sizeof(input), stdin) == NULL){ break; } cp = input; for(argc = 0; argc < MAX_ARGS; argc++){ if((argv[argc] = strtok(cp, delim)) == NULL) break; cp = NULL; } if(strcmp(argv[0], "exit") == 0){ exit(0); } pid_t pid = fork(); if(pid == -1){ perror("fork"); exit(1); }else if(pid == 0){ child(argc, argv); }else{ wait(&status); } } return 0; } void child(int argc, char *argv[MAX_ARGS]{ execvp(argv[0], argv); }

  • c言語に関する質問です

    こんにちは。 私はとある大学の機械工学科の学生です。 先日プログラミングの授業で課題が出されたのですが、さっぱりわかりません。 目的を達成するために、下のプログラム(使ってるものはC++)の間違いを2か所訂正しなさいというものです。 どこをどう直せばいいのか教えてください。 一番左の数字は、ここで指摘しやすくするための行数です。 1 #include <stdio.h> 2 #include <stdlio.h> 3 // 計算処理をするための関数 4 void operation(FILE* ifp,FILE* ofp) 5 { 6 const int LOOPLIMIT = 10000; //ループ最大回数を規定。エラー対策 7 8 if((ifp==NULL)||(ofp==NULL)){//ファイルポインタのエラー処理 9      fprintf(stderr,"[ERROR]null file poimter detected.\n); 10      exit(-1); 11     } 12 13 for(int i=0;i<LOOPLIMIT;i++){//入力ファイルは1万行までサポート 14 if(fscanf(ifp,"%f%f",&a,&b) == EOF) //入力ファイルから数値2個読み込み 15 break;//読み込めなかったら処理を終了 16 float c = a*b; 17 fprintf(ofp,"%g,%g,%g\n",a,b,c); 18   } 19} 20 // メイン関数 21 int main(int argc,char* argv[]) 22 { 23 FILE* ifp = NULL; //入力用ファイルポインタ 24 FILE* ofp = NULL; //出力用ファイルポインタ 25 char* ifile = NULL; //入力ファイル名 26 char* ofile = NULL; //出力ファイル名 27 28 if(argc!=3){ 29 fprintf(stderr,"Usage:%s inputfile outputfile\n,argv[0]); 30 exit(1); 31 } 32 33 ifile = argv[1]; //パラメータの1番目を入力ファイル名 34 ofile = argv[2]; //パラメータの2番目を出力ファイル名 35 36 if((ifp = fopen(ifile,"rt"))==NULL{ //入力ファイルを開く 37 fprintf(stderr,"Can't open file %s\a\n",ifile); //開けなかったら終了 38 exit(2); 39 } 40 if((ifp = fopen(ofile,"wt"))==NULL{ //出力ファイルを開く 41 fprintf(stderr,"Can't open file %s\a\n",ofile); //開けなかったら終了 42 exit(3); 43 } 44 45 operation(ifp,ofp); 46 47 fclose(ofp); 48 fclose(ifp); 49 return(0); 50 } 入力ファイル例(inputdata.txt) 147 0.369 258 0.147 369 0.258 ファイル出力結果の例(outputdata.csv) 147, 0.369, 54.243 258, 0.147, 37.926 369, 0.258, 95.202 画面出力結果の例 147 x 0.369 = 54.243 258 x 0.147 = 37.926 369 x 0.258 = 95.202 ご面倒かもしれませんが、お願いいたします。

  • C言語→C#に変換

    C言語→C#に変換 C言語からC#に変換したいのですが、わからないところがあります。 コマンドライン引数からファイル名とキーワードを入力して、キーワードがある行をアウトプットファイルに書き込むという処理です。 C言語のソースは、 main(int argc,char *argv[]){ FILE *fp; FILE *fpp; int i; char KEYWORD[256]; char buf[256]; //(1)アウトプットファイルのオープン fpp=fopen("output.txt","w"); for(i=1;i<argc-1;i++){ if(strcmp(argv[i],"-a")==0){ //(2)入力ファイルのオープン if((fp=fopen(argv[i],"r"))==NULL){ printf("open error!\n"); exit(1); } } //(3)キーワードの代入 if(strcmp(argv[i],"-b")==0){ strcpy(KEYWORD,argv[i]); } } //(4)一行読み込む while(fgets(buf,sizeof(buf),fp)!=NULL){ //(5)キーワードの条件で文字列抽出 if(strstr(buf,KEYWORD)!=NULL){ //(6)アウトプットファイルに出力 fprintf(fpp,"%s",buf); } } //ファイルクローズ fclose(fp); fclose(fpp); } です。 (3)キーワードの代入と、(5)文字列抽出の部分がネットなどで調べてもよくわかりません。 分かる方いらっしゃいましたら教えていただけると幸いです。 宜しくお願いします。 .

  • C言語 コマンドラインの文字列を調べる方法

    はじめまして。 C言語を学習しています。 PCのOSはWindows XPです。 参考書に、アプリケーションの動作を指定するオプションを指定する方法として、下記の説明とプログラムが載っています。 以下の点でつまづいており、ご教示をお願い致します。 1、プログラム実行結果画面(コマンドプロンプトのような黒い画面。スクリーンショットを添付しております。)に【-a】と入力しようとしましたが、テンキーの【-】を押した時点で画面が消えてしまいます。 どのように操作すれば、参考書のような実行結果が得られるのでしょうか。 2、【argc--;】の部分で、ここでなぜデクリメントを使うのでしょうか。 3、argvは文字配列へのポインタ変数とのことですが、if文のところの【argv[argc][0]】が何を意味しているのか教えてください。 argv[配列の要素]のような書き方ではなく、argvの横に[]が2つある時点で混乱してしまいます。 どうかよろしくお願い致します。 ●参考書による説明 一般的に、コマンドラインにはファイル名の他に、アプリケーションの動作を指定するオプションを指定することがあります。 例えば、Windowsでファイル名を指定して実行で defrag と指定して起動すると、デフラグが起動して何もせずに終了しますが、 defrag c: と指定すると、Cドライブのデフラグを開始します。 また、defrag c: -a と指定すると、Cドライブの分析結果だけを表示します。 このような使い方は、パソコン上級者にはおなじみのやり方です。 この例では、 c: と -a という2つの文字列がコマンドラインに渡され、それをアプリケーション内で解析して、動作を決定しています。 同様のことは、コマンドラインの文字列を調べれば簡単にわかります。 ここでは、-a と -s というオプションの有無を解析する例です。 ●プログラム #include <stdio.h> int main(int argc,char *argv[]) { while (argc > 0) { argc--; if (argv[argc][0] == '-') { if (argv[argc][1] == 'a') printf("-a オプション\n"); if (argv[argc][1] == 's') printf("-s オプション\n"); } } return 0; } このプログラムに -a -s というオプションを与えて実行した結果は次の通りです。 -a オプション -s オプション 同様にすれば、いくつのオプションにでも対応することができます。 また、先頭が - ではない文字列をファイル名として扱うようにすれば、 ファイル名も前項と同様に取得することができます。

  • ポインタについての質問など

    (1) プログラム引数を取る時の記述ですが…. (int argc, char *argv[]) (int argc, char **argv) 本によって記述がまちまちなんです. これらはどう違うのでしょうか? 特に後者の解釈の仕方がいまいち分からないので教えてください. 配列になってないように見えるのですが…. (2) 後者の記述(int argc, char **argv)で書かれたプログラムで ./program.exe okwave と引数を取ったとき,okwaveのoからeまでをfor文やwhile文でたどって何らかの処理をしたいのですが,どうすればいいのでしょうか? (3) ポインタには関係ありませんが,Windowsでncursesは使えないのでしょうか?

  • c言語 DFAのプログラム

    DFAを受理するプログラムを組んでいるのですが、コンパイルして動作させるとすぐに終わってしまいます。 どこがいけないのでしょうか…。助言を求めています。 手探りでやっているのですが、ファイル読み込みなど、基本的な所からわかっていない状態です。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> enum { NFA_0_2_3_5, NFA_0_1_2_3_5_6_7_8_10_11_12, NFA_4_7_8_10, NFA_11_12, NFA_9_12, NFA_13_15_16, NFA_14 }; int regex(char *txt, int idx); int DFA_match(char *txt, int startIndex); int main (int argc, char *argv[]) { int c, i, m, idx; char text[1024], *pattern; FILE *fp; pattern = argv[optind++]; for (i = optind; i < argc; i++) { fp = fopen(argv[i], "r"); if (fp == NULL) { fprintf(stderr, "File %s: open failed.\n", argv[i]); } else { while (fgets(text, sizeof(text), fp) != NULL) { m = 0; for (idx = 0; (idx = regex(text, idx)) >= 0; idx++) { m++; } if (m > 0) { printf("%s: %s", argv[i], text); } } } } return 0; } int DFA_match(char *txt, int startIndex) { int DFAstate = NFA_0_2_3_5; int acceptLen = -1; int i; for (i = startIndex; txt[i] != '\0'; i++) { switch (DFAstate) { case NFA_0_2_3_5: switch(txt[i]){ case 'x': DFAstate = NFA_0_1_2_3_5_6_7_8_10_11_12; break; case 'z': DFAstate = NFA_4_7_8_10; break; default: return acceptLen; } break; case NFA_0_1_2_3_5_6_7_8_10_11_12: switch(txt[i]){ case 'x': DFAstate = NFA_0_1_2_3_5_6_7_8_10_11_12; break; case 'z': DFAstate = NFA_4_7_8_10; break; case 'y': DFAstate = NFA_9_12; break; default: return acceptLen; } break; case NFA_4_7_8_10: switch(txt[i]){ case 'x': DFAstate = NFA_11_12; break; case 'y': DFAstate = NFA_9_12; break; default: return acceptLen; } break; case NFA_11_12: switch(txt[i]){ case 'y': DFAstate = NFA_9_12; break; default: return acceptLen; } break; case NFA_9_12: switch(txt[i]){ case 'y': DFAstate = NFA_13_15_16; acceptLen = i; break; default: return acceptLen; } break; case NFA_13_15_16: switch(txt[i]){ case 'x': DFAstate = NFA_14; break; default: return acceptLen; } break; case NFA_14: switch(txt[i]){ case 'y': DFAstate = NFA_13_15_16; acceptLen = i; break; default: return acceptLen; } break; } } return acceptLen; } int regex(char *txt, int idx) { int i; for (; idx < strlen(txt); idx++) { if ( (i = DFA_match(txt, idx)) > 0) { printf("matched!\n"); return idx; } } return -1; }

  • コンパイルするとエラーに。C言語(改め)

    インクルード 定義 メイン関数 エラー内容 が収まりませんでした; (長すぎてどうすればよいのやら;) int readlines(char *lineptr[], int maxlines) { int len, nlines; char *p, line[MAXLEN]; nlines = 0; while ((len = getline(line, MAXLEN)) > 0) if (nlines >= maxlines || (p = alloc(len)) == NULL) return -1; else { line[len-1] = '\0'; strcpy(p, line); lineptr[nlines++] = p; } return nlines; } char *alloc(int n) { if (allocbuf + ALLOCSIZE - allocp >= n) { allocp += n; return allocp - n; } else return 0; } void kr_qsort(char *v[], int left, int right, int (*comp)(void *, void *)) { int i, last; void swap(char *v[], int i, int j); if (left >= right) return; swap(v, left, (left + right)/2); last = left; for (i = left+1; i <= right; i++) if ((*comp)(v[i], v[left]) < 0) swap(v, ++last, i); swap(v, left, last); kr_qsort(v, left, last-1, comp); kr_qsort(v, last+1, right, comp); } void swap(char *v[], int i, int j) { char *temp; temp = v[i]; v[i] = v[j]; v[j] = temp; } void readargs(int argc, char *argv[]) { char c; int atoi(char *); while (--argc > 0 && (c = (*++argv)[0] == '-' || c == '+') { if (c == '-' && !isdigit(*(argv[0]+1))) while (c = *++argv[0]) switch (c) { case 'd': option |= DIR; break; case 'f': option |= FOLD; break; case 'n': option |= NUMERIC; break; case 'r': option |= DECR; break; default: printf("sort: illegal option %c\n", c); error("Usage: sort -dfnr [+pos1] [-pos2]"); break; } else if (c == '-') pos2 = atoi(argv[0]+1); else if ((pos1 = atoi(argv[0]+1)) < 0) error("Usage: sort -dfnr [+pos1] [-pos2]"); } if (argc || pos1 > pos2) error("Usage: sort -dfnr [+pos1] [-pos2]"); } } void writelines(char *lineptr[], int nlines, int order) { int i; if (order) for (i = nlines-1; i >= 0; i--) printf("%s\n", lineptr[i]); else for (i = 0; i < nlines; i++) printf("%s\n", lineptr[i]); } int charcmp(char *s, char *t) { char a, b; int i, j, endpos; int option, pos1, pos2; int fold = (option & FOLD) ? 1 : 0; int dir = (option & DIR) ? 1 : 0; i = j = pos1; if (pos2 > 0) endpos = pos2; else if ((endpos = strlen(s)) > strlen(t)) endpos = strlen(t); do { if (dir) { while (i < endpos && !isalnum(s[i]) && s[i] != ' ' && s[i] != '\0') i++; while (j < endpos && !isalnum(t[j]) && t[j] != ' ' && t[j] != '\0') j++; } if (i < endpos && j < endpos) { a = fold ? tolower(s[i]) : s[i]; i++; b = fold ? tolower(t[j]) : t[j]; j++; if (a == b && a == '\0') return 0; } } while (a == b && i < endpos && j < endpos); return a - b; } int numcmp(char *s1, char *s2) { double v1, v2; char str[MAXSTR]; substr(s1, str, MAXSTR); v1 = atof(str); substr(s2, str, MAXSTR); v2 = atof(str); if (v1 < v2) return -1; else if (v1 > v2) return 1; else return 0; } void substr(char *s, char *str, int maxstr) { int i, j, len; extern int pos1, pos2; len = strlen(s); if (pos2 > 0 && len > pos2) len = pos2; else if (pos2 > 0 && len > pos2) error("substr: string too short"); for (j = 0, i = pos1; i < len; i++, j++) str[j] = s[i]; str[j] = '\0'; } int getline (char s[], int lim) { int c, i; i = 0; while (--lim > 0 && (c=getchar()) != EOF && c != '\n') s[i++] = c; if (c == '\n') s[i++] = c; s[i] = '\0'; return i; } void error(char *s) { printf("%s\n", s); exit(1); }

専門家に質問してみよう