Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 传递指针变量以存储字符串数组(命令行参数)_C_Pointers_Command Line_Multidimensional Array_Argument Passing - Fatal编程技术网

C 传递指针变量以存储字符串数组(命令行参数)

C 传递指针变量以存储字符串数组(命令行参数),c,pointers,command-line,multidimensional-array,argument-passing,C,Pointers,Command Line,Multidimensional Array,Argument Passing,我的头撞到墙上已经有好几个小时了,我需要你的帮助。在我的作业中,我应该编写一个函数,将字符串拆分为以空格分隔的标记。这些令牌被复制到动态分配的字符串数组中。字符串作为参数传递,第二个参数是指向字符串数组(char***argv)的指针变量。我很难理解如何处理这个三维数组以及如何动态分配它。以下是相关代码: #include <stdio.h> #include <stdlib.h> int main(void) { char **args = NULL; char c

我的头撞到墙上已经有好几个小时了,我需要你的帮助。在我的作业中,我应该编写一个函数,将字符串拆分为以空格分隔的标记。这些令牌被复制到动态分配的字符串数组中。字符串作为参数传递,第二个参数是指向字符串数组(char***argv)的指针变量。我很难理解如何处理这个三维数组以及如何动态分配它。以下是相关代码:

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

int main(void)
{

char **args = NULL;
char cmdline[] = "cmdline -s 20 -r -t parameter -p 20 filename";
int count = parse_cmdline(&args, cmdline);

我已经读了很多关于指针、字符串、数组和多维数组的书,但我似乎无法理解。有一件事我真的不明白,为什么指针作为(&args)传递,为什么不作为数组指针传递呢?我也不确定我是否正确使用了memcpy。

除了使用
sizeof
而不是
strlen
之类的错误用法之外,让我们先看看其他几个问题


为什么
&args

有一件事我真的不明白,为什么指针作为(&args)传递,为什么不作为数组指针传递呢

看看你的陈述:

char **args = NULL;
这告诉你什么

A.)
char**args
B.)
char**args=NULL
它已初始化,并指向NULL。在您的函数中,您将它指向的内容从NULL更新为realloc返回的新地址

这里有一点非常重要:你要更新它指向的内容!如果不传递args的地址,则无法告诉main新位置在哪里

你在复制一份被传递的东西

如果它指向某个地址,例如来自以前的malloc,您可以更新它指向的内容,但无法重新定位,因为您无法更新指针本身。也就是说:回到主要位置,它仍然指向旧位置

你的目标是:

args * * 0x123e0a -> [0] 0x123fa00 -> 0x12fbae0 - 0x12fbae8 cmdline [1] 0x123fa08 -> 0x12fbae9 - 0x12fbaec -s [2] 0x123fa10 -> 0x12fcae0 - 0x12fcae3 20 [3] 0x123fa18 -> 0x12fbad8 - 0x12fbadb -r ...
 foo = argv[i];
*foo = malloc(...);
也就是说:
args
和任何变量一样,在所有步骤中都有一个地址。你可以说:

printf("Address of args=%p\n", (void*)&args);
2,3之间的差异。四,。上面是

  • 在第2点。变量没有指向任何东西。它未初始化。1
  • 在第3点。它已初始化,但它不指向地址,但为空。最后
  • 在第4点。它具有malloc返回的位置地址
一,。除非它是静态的、全局的等等,否则它将为空


现在我们可以看看
char**args=NULL

1. char **args;
2. char **args = NULL;
3. char **args = malloc(1);
4. char **args = malloc(1);
   args[0] = malloc(9);
回到主参数中,仍然有地址
0x123400
,但它不再指向NULL,而是指向最后一个realloc()的地址,例如
0x1234bd


正在访问指向指针数组的指针。。。
现在,第二个问题是如何正确访问数组元素,因为您有一个指向指针变量而不是指针变量的指针

ptr->args
vs
args

在主函数中,您可以通过以下方式访问args:

等等

然而,在parse_cmdline()中存在一些怪癖。首先看看这个:

*argv
在这里,您可以使用
*
取消对argv的引用,从main访问args。到现在为止,一直都还不错。但是你说:

*argv[i]
这会变得很糟糕,为了理解原因,你必须看看。如您所见,数组下标的优先级高于
*
。因此,您正在索引的是argv,而不是它所指向的,然后您尝试取消对索引地址的引用。比如:

args * * 0x123e0a -> [0] 0x123fa00 -> 0x12fbae0 - 0x12fbae8 cmdline [1] 0x123fa08 -> 0x12fbae9 - 0x12fbaec -s [2] 0x123fa10 -> 0x12fcae0 - 0x12fcae3 20 [3] 0x123fa18 -> 0x12fbad8 - 0x12fbadb -r ...
 foo = argv[i];
*foo = malloc(...);
要解决此问题,请将解引用封装到括号中,并为其结果编制索引:

(*argv)[i] = malloc(...);
/* and */
memcpy((*argv)[i], token, strlen(token) + 1);
从简单的数学角度考虑可能更容易:

12 + 4 / 2
你想把12和4的和除以2。由于
/
具有更高的优先级,您需要添加括号:

(12 + 4) / 2

sizeof
最后,如注释中所述,
sizeof
不会给出字符串的长度。在您的代码中,它将为您提供字符指针的大小。例如:指针的大小

char foo[32] = "ab";
int bar[64];
char *baz;

sizeof foo => 32
sizeof bar => 64 * size of int e.g. 64 * 8 = 512
sizeof baz =>  8 (or 4 or what ever the size of a pointer is in 
                  current environment.)
使用strlen或类似的工具。你也可以为教育目的制作自己的strlen。复制时,请记住还要复制终止的空字节。即:

memcpy((*argv)[i], token, strlen(token) + 1);
                                          |
                                          +----- Include 0x00 at end of token.
函数的作用是:将分隔符替换为
0x00
,因此不需要手动添加分隔符。这也是为什么可以使用strlen()。如果不终止null,除非您事先知道长度,否则没有任何方法


工作吧
这是一个典型的主题,你只需要不断努力,直到它消失。虽然是的,但是有更简单的方法来解决它,例如,通过返回数组而不是通过ref等来更新数组,这是一种教育性的方法,它迫使您学习指针、参数等。在某种程度上,您可以通过使其工作学到很多东西

使用
printf()
帮助您。大量印刷。打印字符串长度、变量大小等,在本例中打印地址。例如,主要:

printf("args=%p\n", (void*)&args);
如果你被卡住了,那就退后一步。尝试传递
args
,而不是
&args
,然后处理这个问题。还可以尝试在函数中使用临时指针:

int parse_cmdline(char ***argv, char *input)
{
        int i = 0;
        char **argx = *argv; /* Temporary local. */
        char *token = strtok(input, " ");

        fprintf(stderr, "argv=%p\n", (void*)argv);

        while (token != NULL) {
                fprintf(stderr,
                        "%15s, sizeof=%u strlen=%u\n",
                        token, sizeof(token), strlen(token)
                );
                /* Now you can refer argx like you would args in main(). 
                 * as in: argx[i] instead of (*argv)[i] etc.
                 */
        }
        /* Update pointer before return. */
        *argv = argx;
        return i;
}
#包括
#包括
int parse_cmdline(字符***argv,字符*输入);
内部主(空){
字符**args=NULL;
char cmdline[]=“cmdline-s 20-r-t参数-p 20文件名”;
int count=parse_cmdline(&args,cmdline);

对于(int i=0;如果这是作业,我将给您一个提示。函数声明可以是
int parse\u cmdline(char**argv,const char*input)
。根据这一点,尝试对传递参数的方式进行反向工程?Sizeof()不会给出字符串的长度。我想您需要strlen()@马赫什:你建议他如何用这个签名更新
args
?非常感谢你非常详细的回答。我感谢你花时间尽可能清楚地说明。我已经学到了很多,但我会仔细阅读你的答案,直到我完全理解
12 + 4 / 2
(12 + 4) / 2
char foo[32] = "ab";
int bar[64];
char *baz;

sizeof foo => 32
sizeof bar => 64 * size of int e.g. 64 * 8 = 512
sizeof baz =>  8 (or 4 or what ever the size of a pointer is in 
                  current environment.)
memcpy((*argv)[i], token, strlen(token) + 1);
                                          |
                                          +----- Include 0x00 at end of token.
printf("args=%p\n", (void*)&args);
int parse_cmdline(char ***argv, char *input)
{
        int i = 0;
        char **argx = *argv; /* Temporary local. */
        char *token = strtok(input, " ");

        fprintf(stderr, "argv=%p\n", (void*)argv);

        while (token != NULL) {
                fprintf(stderr,
                        "%15s, sizeof=%u strlen=%u\n",
                        token, sizeof(token), strlen(token)
                );
                /* Now you can refer argx like you would args in main(). 
                 * as in: argx[i] instead of (*argv)[i] etc.
                 */
        }
        /* Update pointer before return. */
        *argv = argx;
        return i;
}
#include <stdio.h>
#include <stdlib.h>

int parse_cmdline(char ***argv, char *input);

int main(void){
    char **args = NULL;
    char cmdline[] = "cmdline -s 20 -r -t parameter -p 20 filename";
    int count = parse_cmdline(&args, cmdline);
    for(int i = 0;i<count;++i)
        printf("%s\n", args[i]);
    printf("\n");
    return 0;
}

#include <string.h>

int parse_cmdline(char ***argv, char *input){
    int i=0;
    char *token=strtok(input," ");

    while (token!=NULL) {
        int len = strlen(token);
        *argv=realloc(*argv,(i+1)*sizeof(char*));
        (*argv)[i]=malloc(len+1);
        strcpy((*argv)[i++],token);
        token=strtok(NULL," ");
    }
    return i;
}