-3

我试图从命令行参数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位处理器,Windows 7操作系统上使用VS 2015社区与Visual C++编译器。

我的问题:

  • 我应如何通过CMD和args []引用?
  • 是否有任何广泛接受的成语处理这种情况?

我看了槽数的similiar问题,但没有找到,在这种情况下有效的解决方案,如果问题是重复的,告诉我,我会关闭it.Since我'新的stackoverflow任何问题格式化技巧将不胜感激。干杯! (:。

+0

引入另一个间接层次。 – alk

+0

为什么有人会通过引用传递指针? – farukdgn

+0

@farukdgn:在函数内部分配内存,访问函数在调用者内部。 – alk

回答

0

strtok_s()返回指针到它的解析缓冲区(input这里)上getCmd()堆栈

input生活它死的那一刻getCmd()回报从此指向input地址,并已被存储在。 args的元素没有指向有效的内存了。

代码需要分配记忆犹新,复制什么strtok_s()返回一个指针。

看看ow可以这样做:

#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

我默默地认为它会是'strtok_r()'被Redmond的一些公司重新命名....:} @AndrewHenle – alk

+0

@alk。安德鲁亨利:不是这次。它是可选的“绑定检查接口”的一部分:http://port70.net/~nsz/c/c11/n1570.html#K.3.7.3.1 – Olaf

1

有几种不同的方法可以解决这个问题。虽然您可以自由地为cmdargs数组动态分配内存,但实际上并不需要,对于有限的内存量,您可以对所有内存使用静态声明。不需要单独的input阵列,您可以使用cmd来达到该目的,然后标记为cmd。这提供了在调用strtok之后将第一个令牌以nul结尾的保留在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变量/函数名称更改为全部小写。C++的名字为camelCase。见例如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 

看一下它,并让我知道如果您有任何其他问题。