-3

私はコマンドラインのargs int main(int argc, char *argv[])と同様の方法でキーボードからコマンドを取得しようとしていますが、別の機能です。私が解析してgetCmd()の機能の範囲内でそれらを印刷すると、すべての外観と動作が意図どおりに行われますが、メイン関数に戻るとすぐにゴミの束になります。私の質問はコードの下にあります。参照の配列の配列を渡す

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

void getCmd(char *cmd, char *args[]) 
{ 
    char input[81] = { 0 }; 
    char *next_token = NULL; 
    printf("$ "); 
    fgets(input, 81, stdin); 
    input[strcspn(input, "\n")] = 0; 
    cmd = strtok_s(input, " ", &next_token); 
    if (!strcmp(cmd, "mv")) 
    { 
     args[0] = strtok_s(NULL, " ", &next_token); 
     args[1] = strtok_s(NULL, " ", &next_token); 
     printf("\n\n%s\n%s\n%s\n\n", cmd, args[0], args[1]); 
    } 
} 

int main(void) 
{ 
    char *cmd = NULL, *args[5]; 

    cmd = (char *)calloc(20,sizeof(char)); 
    for (size_t i = 0; i < (size_t)5; i++) 
    { 
     args[i] = (char *)calloc(20,sizeof(char)); 
    } 
    getCmd(cmd, args); 
    printf("\n\n%s \n%s\n%s", cmd, args[0], args[1]); 
    return 0; 
} 

私は、その関連するとは思わないが、私は、64ビットプロセッサ上のVisual C++コンパイラを使用してWindows 7 OSをVS 2015コミュニティを使用しています。

私の質問は:

  • は、どのように私は、参照することにより、CMDとargs []を渡す必要がありますか?
  • このような状況に対応する広く受け入れられているイディオムはありますか?

私は似質問の谷の数を見てきたし、質問が重複している場合は、この文脈で働く解決策を見つけるを教え、私はit.Since Iを閉じますができませんでしたどのような質問の書式設定のヒントをいただければ幸いです。乾杯! (:。。。ここでは、パースのバッファへの

+0

間接参照の別のレベルを導入します。 – alk

+0

誰も参照によってポインタを渡すのはなぜですか? – farukdgn

+0

@farukdgn:関数内でメモリを割り当て、アクセスは呼び出し元の内部にあります。 – alk

答えて

0

strtok_s()リターンポインタ(inputgetCmd()スタック上

input生活はその後からinputに向いてアドレスに瞬間にgetCmd()リターンを死に、それが中に保存されていましたargsの要素は、任意のより有効なメモリを指していません。

コードのニーズは、新鮮なメモリを割り当て、strtok_s()はへのポインタを返したものをコピーしてください。

をこれを行うことができるかどうかを見てください:

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

void getCmd(char **pcmd, char *args[], size_t s) 
{ 
    char input[81] = { 0 }; 
    char *next_token = NULL; 
    printf("$ "); 
    fgets(input, 81, stdin); 
    input[strcspn(input, "\n")] = 0; 
    (*pcmd) = _strdup(strtok_s(input, " ", &next_token)); 
    if (!strcmp(*pcmd, "mv")) 
    { 
     args[0] = _strdup(strtok_s(NULL, " ", &next_token)); 
     args[1] = _strdup(strtok_s(NULL, " ", &next_token)); 
     printf("\n\n%s\n%s\n%s\n\n", *pcmd, args[0], args[1]); 
    } 
} 


#define ARGS_MAX (5) 

int main(void) 
{ 
    char *cmd, *args[ARGS_MAX] = {0}; 

    getCmd(&cmd, args, ARGS_MAX); 
    printf("\n\n%s \n%s\n%s", cmd, args[0], args[1]); 

    /* Clean up. */ 
    free(cmd); 
    for (size_t i = 0; i < ARGS_MAX; ++i) 
    { 
     free(args[i]); 
    } 

    return 0; 
} 
+1

この 'strtok_s'とは何ですか? ;-) –

+0

私は静かにRedmondの会社によって名前が変更された 'strtok_r()'と仮定しました....:} @AndrewHenle – alk

+0

@alk。 AndrewHenle:今回はありません。オプションの「バウンドチェックインターフェイス」の一部です:http://port70.net/~nsz/c/c11/n1570.html#K.3.7.3.1 – Olaf

1

問題に近づく方法はいくつかあります。 cmdargs配列に動的にメモリを割り当てることは自由ですが、実際には必要ありません。この限られた量のメモリに対して、すべての静的宣言を使用できます。別のinput配列は必要ありません。その目的ではcmdを使用し、次にcmdをトークン化します。これにより、strtokの後に最初のトークンがヌル終了cmdに残す利点があります。

注:以下の例ではstrtokが使用されている、strtok_sはC11で、オプションのコンパイラ加えた、残念ながら、私は、そのオプションを実装して、コンパイラを持っていないので、私はstrtokでテスト。 VSの変更を簡単に行うことができます。

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

enum { NARGS = 5, MAXC = 128 }; 

size_t getcmd (char *cmd, char (*args)[MAXC]); 

int main (void) { 

    char cmd[MAXC] = "", args[NARGS][MAXC] = { "" }; 
    size_t i, n; 

    if (!(n = getcmd (cmd, args))) return 1; 

    printf (" %s", cmd); 
    for (i = 0; i < n; i++) 
     printf(" %s", args[i]); 
    putchar ('\n'); 

    return 0; 
} 

size_t getcmd (char *cmd, char (*args)[MAXC]) 
{ 
    char *delim = " ,.\t\n"; 
    char *p = NULL; 
    size_t idx = 0; 

    printf ("$ "); 
    if (!fgets (cmd, MAXC, stdin)) { 
     fprintf (stderr, "error: invalid input.\n"); 
     return 0; 
    } 

    strtok (cmd, delim);   /* terminate after 1st token */ 

    for (p = strtok (NULL, delim); p; p = strtok (NULL, delim)) { 
     strncpy (args[idx++], p, MAXC); /* limit to avail chars */ 
     if (idx == NARGS) break; /* limit to available bounds */ 
    } 

    return idx; 
} 

注上記、getcmdの戻り型はsize_tあります。成功/失敗の表示だけでなく、必要な情報(ここでの引数の数)を返すために、意味のある型を常に選択します。また、Cスタイルガイドの不具合に気をつけてください。camelCase可変/関数名はすべて小文字にすることをお勧めします。camelCaseの名前はC++のままにしておいてください。例えば、 NASA - C Style Guide, 1994

使用例/出力

$ ./bin/getcmd 
$ mv /this/here/file /that/there/file 
    mv /this/here/file /that/there/file 

$ ./bin/getcmd 
$ mv -i --strip-trailing-slashes /this/here/file /that/there/file 
    mv -i --strip-trailing-slashes /this/here/file /that/there/file 

はそれを上に見て、もし、何か質問があれば私に知らせてください。