在C中悬空指针和字符数组的麻烦

时间:2010-03-02 02:47:39

标签: c pointers dangling-pointer

main(){
   char *cmd1[20] = {NULL};
   int x = parse_command(cmd1);
   printf("%s\ ",cmd1[0]);
}

parse_command(char *inTempString){
   char tempString[256];
   (call to function that assigns a string to tempString)
   cmd1[0] = tempString;
}

cmd1[0]内打印main时出现问题。我很确定这是一个悬空指针错误。我真的不知道如何解决它。

5 个答案:

答案 0 :(得分:4)

您的计划存在两个问题。

首先,当你说:

char *cmd1[20] = {NULL};

cmd1是一个包含指向char的20个指针的数组。这意味着[0,20]中cmd1[i]的{​​{1}}是指向i的指针。

C中有一条规则,即将数组传递给函数只会将指向数组的第一个元素的指针传递给函数。即,如果您的代码如下:

char

然后函数调用int ai[20]; f(ai); ai的类型为f(ai);,传递给int *的指针等于f(),即&ai[0]的第一个元素ai

所以,当你这样做时:

parse_command(cmd1);

您立即知道传递给parse_command()的“事物”是&cmd1[0],即指向cmd1的第一个元素的指针。由于cmd1[0]的类型为char *,因此您将char **传递给parse_command。因此,您的声明:

parse_command(char *inTempString);

错了,你应该这样做:

parse_command(char **inTempString);

以匹配您的电话。这假定parse_command()将解析cmd1中的多个值。如果是这种情况,您还应该将cmd1中的元素数量传递给parse_commnd() - 因为它无法知道cmd1有多少元素。

你的第二个问题是你不能从C中的函数返回局部变量的地址。如上所述,除了函数调用,在C中返回数组,或者在C中为数组赋值也使数组的名称“衰减”为指向其第一个元素的指针。

所以鉴于你的功能:

/* changed inTempString to cmd1 because that's what you probably meant */
int parse_command(char *cmd1)
{
    char tempString[256];
    /* call to function that assigns a string to tempString */
    cmd1[0] = tempString;
    /* you need to return an int from here */
}

tempString分配中的cmd1[0]实际上是&tempString[0],即指向tempString的第一个元素的指针。但是,因为函数返回后tempString被销毁,指针就变为无效。您以后不能使用该值。

实际上,在C中,数组的名称在所有情况下都衰减为指向其第一个元素的指针,除了:

  • 用作sizeof运算符的操作数和
  • 用作地址(&)运算符
  • 的操作数

更确切地说,在对象上下文中,数组的名称不会衰减为指针,而在值上下文中,它会衰减为指针。有关详细信息,请参阅this

现在,您应该如何解决第二个问题?这取决于您可以在parse_command()中动态分配内存,并将该内存分配给cmd1[0],或者您可以在函数中生成tempString static。由于函数返回时函数中的static变量不会被销毁,因此可以继续使用指向它的指针。动态分配更多工作 - 您需要担心分配失败,并且需要记住在完成时释放指针。 static数组更容易,但您必须要小心,因为对parse_command的另一次调用将覆盖该数组,使其不那么通用。

假设您想要使用“动态内存”路径,可以使用以下方案:

#include <stdio.h> /* printf */
#include <stdlib.h> /* malloc and free */

int main(void) /* main returns int */
{
    char *cmd1[20] = {NULL};
    /* number of commands.  "sizeof cmd1" is the number of bytes
       used by the cmd1 array, and "sizeof cmd1[0]" is the number
       of bytes used by one element of the array.  The division
       gives you the number of elements.  This is 20 of course
       but doing it this way makes sure that changing "20" to any
       number works. */
    size_t ncmds = sizeof cmd1 / sizeof cmd1[0];
    /* pass the number of commands to "parse_command", since
       it can't know otherwise */
    int x = parse_command(cmd1, ncmds);
    int i;
    for (i=0; i < x; ++i) {
        printf("%s ", cmd1[i]);
        free(cmd1[i]);
    }
    return 0; /* return a value from main */
}

int parse_command(char **cmd1, size_t ncmds)
{
    char *tempString; /* we will malloc this */
    int i; /* the number of mallocs done successfully */
    tempString = malloc(...);
    if (tempString == NULL) {
    /* failure, handle gracefully */
    } else {
        ++i; /* make sure i doesn't exceed or equal ncmds */
    }
    cmd1[0] = tempString;
    /* do the above as many times as you need */
    return i; /* the number successfully assigned to */
}

答案 1 :(得分:0)

你在main中将cmd1声明为char ** - 也就是指向char的指针。但是,然后将它传递给parse_command,您已将其定义为使用char *;指向char的指针。

这只能编译,因为指针到任何东西的自动转换为指向char的指针。这是旧版C的历史文物,使用'char *'代替'void *';在您的情况下,它只是意味着编译器忽略您所做的类型错误而不是向您报告。

答案 2 :(得分:0)

是的,你不能这样做。

char tempString[256];

在函数parse_command中声明堆栈上的变量,该变量超出范围,当parse_command返回时,指向它的指针不再有效。

您需要在堆上分配命令字符串,以便在parse_command返回时它仍然有效。这是一种方式。

parse_command(char *inTempString){
   char tempString[256];
   (call to function that assigns a string to tempString)

   int cb = strlen(tempString)+1;
   cmd1[0] = (char *)malloc(cb);
   strcpy(cmd1[0], tempString);
}

您还应在主要退出前致电free(cmd[0])

除此之外,此代码无法编译。您无法从cmd1[0]函数中引用parse_command。当你尝试将cmd1传递给parse_command时,你应该得到一个类型不匹配,如果你想从parse_command返回一个char *那么它应该被声明为char **一个论点,更像是这样。

parse_command(char **pcmd){
   char tempString[256];
   (call to function that assigns a string to tempString)

   int cb = strlen(tempString)+1;
   pcmd[0] = (char *)malloc(cb);
   strcpy(pcmd[0], tempString);
}

答案 3 :(得分:0)

这样的事情会起作用:

parse_command(char **inTempString){
        static char tempString[256];
        strcpy(tempString,"some string you want to copy");
        inTempString[0] = tempString;
}
  • 在你的代码中,tempString不会 函数返回后存在。您 即使在之后也需要保持活力 功能返回。你可以分配 空间动态和解除分配 稍后或者您可以将其声明为 静态的。
  • 您还需要更改类型 参数inTempString从char *到 字符**。

答案 4 :(得分:0)

您正尝试从cmd1访问位于main范围内的parse_command变量。

我想说至少cmd1[0]看起来像一个整数,因为它没有用该方法声明。

cmd1被声明为array of char*,但方法的参数为char*,可能是pointer to char array {{1} }。

将char数组复制到另一个char数组的最佳方法是使用pointer to array of char*memcpy或接受指向src,dest和size的指针的类似方法。