• ベストアンサー

C言語の基礎

1.main関数の引数である、int argc と char **argvはどのように使用するのでしょうか? 2.特定の文字列(UserID)を入力し,それぞれの文字が使用可能文字列(数字とアルファベット(大文字小文字)と一致したら,使用可能文字列(配列)から削除し,残りの配列の文字を使って6~8文字のパスワードを作成するにはどのように関数を設計すればいいでしょうか? パスワードを作成するのに時刻を種とした乱数を使用してある一文字を取得するという方法を考えました。 srand(unsigned time(NULL); パスワードはUserIDに使用した文字を含まないようにしたいので,(使用可能文字列)-(UserID)= パスワードに使用できる文字列になると思うのですが, 配列-配列なんてできるのでしょうか?実力不足のため,変な質問をして申し訳ございません。どうかご教授ください。

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

  • ベストアンサー
  • hitomura
  • ベストアンサー率48% (325/664)
回答No.5

この質問は参照URLの続きですよね? こうしたほうがいいと言った立場上、答えさせていただきます。 あのアドバイスをしたとき、私の頭にあったのは次のようなソースでした。 (ちなみに、このソースは必要な処理を色々抜かしてある上、空白を全角で入力しているためそのままでは動きません。) /*使用可能な文字テーブル:62だと乱数に偏りが出るため64にしてある*/ char g_acTable[64]; /*=10(数字)+26(大文字)+26(小文字)+2(穴埋め)*/ main( int argc, char** argv ) {  int i;  char szPassword[8]; /*パスワード格納スペース*/  int nLength;    /*パスワードの文字列長*/  int nCount=0;    /*処理中の文字が何文字目か?*/  int nLetter;    /*文字候補がテーブルの何文字目か?*/  /*使用可能な文字テーブルの初期化*/  for(i=0;i<10;i++){   g_acTable[i]='0'+i;  }  for(i=0;i<26;i++){   g_acTable[i+10]='A'+i;  }  for(i=0;i<26;i++){   g_acTable[i+36]='a'+i;  }  g_acTable[62]=g_acTable[63]=-1;  /*パラメータのチェックルーチンがここに入る*/  /*ユーザーIDと一致する文字を使わないようにする*/  for(i=0;argv[1][i]!=0;i++){   if(isdigit(argv[1][i])){    g_acTable[argv[1][i]-'0']=-1;   }else if(isupper(argv[1][i])){    g_acTable[argv[1][i]-'A'+10]=-1;   }else if(islower(argv[1][i])){    g_acTable[argv[1][i]-'a'+36]=-1;   }  }  nLength=atoi(argv[2]);  /*パスワード作成*/  while(nCount<nLength){   nLetter=rand()%64;   /*パスワードに使えない文字だった場合は乱数の出しなおし*/   if(g_acTable[nLetter]==-1){    continue;   }   szPassword[nCount]=nLetter;   nCount++;  }  /*完成したパスワードの表示*/  printf("Password for %s : %s\n",argv[1],szPassword); }

kiroro302
質問者

お礼

前回に引き続き、ご丁寧なご教授を賜り,ありがとうございます。パラメータのチェックルーチンは if(1==argc) return help() (←help()関数は単に使用方法を表示したもの) としました。使用可能な文字テーブル上の、UserIDに使用されている文字を使用できなくしてしまう方法はすばらしいですね。私が関数を作ると長くなってしまい効率が悪いプログラムになってしまっているようです。UserIDと一致する文字を使わないようにするやり方は参考にさせていただきます。もう少しでできそうですので,がんばってみます。どうもありがとうございました。今後もよろしくお願いいたします。

kiroro302
質問者

補足

すみません。ちょっとわからないので、おしえてください。 パスワードを作成するのに時間を種にした乱数を使用してある一文字を取得するのに while(nCount<nLength){ srand(ungigned int time(NULL)); nLetter=rand()%64; -------------------------- というところで、%64の意味がわかりません。%64は余りという意味でしょうか? rand()は0から32767までの数値を返すのですよね。RAND_MAXは定義されている定数で、2の15乗‐1に変換されるということを本で見たのですが,どういうことでしょうか? %64とすると0~63までの乱数を取得できるということになるということですが、この意味が理解できないのですが、ご教授願えますでしょうか?あまりに知識がなさ過ぎて申し訳ありません。よろしくお願いいたします。

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

その他の回答 (4)

  • madman
  • ベストアンサー率24% (612/2465)
回答No.4

文字列の引き算関数を作ってみました。 あと、2.で使えるような感じのソースを書いてみました。 char *subtraction(char *retval, char *userID); で引数の、前の文字列-後ろの文字列の結果が関数値で返ります。 呼出先よりこの関数を上に置くか、上の形でプロトタイプ宣言してください。 まあ、普通パスワードはcrypt関数を使うんだけど、標準ではライブラリにくっついていないんで... 後は自分で調べて勉強してください。 --- #include <stdio.h> #include <strings.h> #define BASE_MAX 62 char base[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; char *subtraction(char *retval, char *userID) { int i, cnt; char *cret; for (i=0; i<strlen(userID); i++) { cret = strchr(retval, userID[i]); cnt = (int)(cret - retval); if (cret && cnt != strlen(retval)) { strcpy(&retval[cnt], &cret[1]); } else if(cnt == strlen(retval)){ base[cnt-1] = 0; } } return retval; } main(){ char tmp[BASE_MAX]; strcpy(tmp, base); printf("%s\n",subtraction("sodivubv", tmp)); strcpy(tmp, base); printf("%s\n",subtraction("zoyivubv", tmp)); }

kiroro302
質問者

お礼

ご回答ありがとうございます。私もいろいろ考えてみました。使用できる文字を配列に入れて,UserIDの文字と比較し,等しかったらフラグを1にし、不等だったら、0にして、フラグが0だったら、usablestrという配列にいれて、パスワードに使用できる文字の配列をつくるというような、関数を考えてみました。 void makecharset(char *account, char *usablestr) { int i, j, k, n; const char c[62] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; n = 0; for( i=0; i < 62; i++ ) { k=0; for( j=0; j < strlen(account); j++ ) { if ( account[j] == c[i] ) { k=1; break; } } if(0 == k) usablestr[n++] = c[i]; } usablestr[n] = '\0'; } ご教授いただいたソースを自分なりに消化し,参考させていただきます。 ご丁寧にご回答いただき本当にありがとうございました。これからもよろしくお願いいたします。

すると、全ての回答が全文表示されます。
  • sssohei
  • ベストアンサー率33% (33/98)
回答No.3

> どのように関数を設計 問題をどのように解決すればいいか、分解してみてください。 > 配列-配列なんてできるのでしょうか C++ でなら可能と言えば可能です^^; 配列の変わりにvectorを使って、、、(とりあえず、それるので、以下略でおいておきます。 Cでやる場合、擬似的なのですが、一致したら、次以降の奴で上書きするという感じで書きます。 # いらばいデータのぶん詰めてしまう、と言うことです。 char array[size] int i, pos=0; for(i=0; i<size; i++) {  if (array[i] が UserIDに含まれていなければ) {   array[pos] = array[i];   pos++;  } } for(i=pos; i<size; i++) array[i] = 0; // 残りを破棄する array_size = pos; // 新しい配列の大きさはpos

kiroro302
質問者

お礼

ありがとうございます。大変参考になります。いらないデータの上から上書きして詰めてしまい、残りの要素に0を代入して,破棄するのですね。この"残りの要素に0を代入して破棄する"というような、アイデアがなかなか浮かびません。センスないのでしょうか?やはり私のようなものは、たくさんソースを書いて,いろいろ試してみて経験を積無しかないなと思います。地道にやっていくつもりですので,これからもよろしくお願いいたします。

すると、全ての回答が全文表示されます。
  • syo_2910
  • ベストアンサー率21% (3/14)
回答No.2

2.の回答です。 見当違いだったらごめんなさい。 まず使用可能文字列の配列を2次元以上に取ります 例えばこんな風に struct TBL { int flag ; char moji[9] ; }Tbl[256] ; 文字数最大8文字までの使用可能文字列を 256用意します。 UserIDと比較を行い、一致した使用可能文字列には flagをONすることによって、その文字列を 使わないようにします。 また、UserIDと比較は完全一致のみで あれば、strcmp関数等関数で比較を行えば用意にできると 思いますが。 UserID+他の文字等の場合は、一文字ずつ比較する 関数を作る必要があります。 こんなもんでどうでしょうか?

kiroro302
質問者

お礼

ご丁寧に補足していただきありがとうございます。構造体を使うということは、思案しなかったので,大変参考になります。私の力ではまだ構造体をうまく使いこなせそうにないのですが,本を読みながら考えてみたいと思います。いっしょに勉強している友達も、構造体を使用している人はいないみたいなので、挑戦してみます。どうもありがとうござます。最近だんだん勉強が面白くなってきつつあります。またつまずいてしまうかもしれませんが,これからもよろしくお願いいたします。

すると、全ての回答が全文表示されます。
  • syo_2910
  • ベストアンサー率21% (3/14)
回答No.1

まずは、1.質問から回答します あまり綺麗なプログラムではありませんが main(argc, argv) int argc ; char *argv[] ; { int i ; if(argc<= 1) { printf("引数がありません\n") ; } else { for(i = 1;i < argc;i ++) printf("引数は%s\n",argv[i]) ; } } 例えば、上記のようなプログラムが fnc.exeのmain関数だったとします。 このとき、 fnc.exe(Enter) と、実行すると argc=1,argv[0]="fnc.exe"が渡されます。 もしも、fnc.exe a b(enter) とすると argc=3, argv[0]="fnc.exe" argv[1]="a" argv[2]="b"が渡されます。 このように、argc,argvを使うと main関数(EXE)へ引数を渡すことができます。 ※ デバッグしていないので動かないプログラムだったら   ごめんなさい

kiroro302
質問者

お礼

ご回答ありがとうございます。fnc.exe a b(enter)とすると argc=3, argv[0]="fnc.exe" argv[1]="a" argv[2]="b"が渡されます ということですが、argc=3の3は引数の数が3つあるということでしょうか? argv[0]には実行するファイルそのものを渡されるのですね。この配列が勝手に作られるのはC言語の仕様なのでしょうか?

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

関連するQ&A