2010-09-15 99 views
2

由于某些原因,我无法解释,字符数组中的每个项目...等于最后添加的项目...例如progArgs [0]通过progArgs [size]包含最后一项的值。将std :: list转换为char * [size]

我无法弄清楚我在做什么对我来说是错误的。有什么建议么?

int count = 0; 
char *progArgs[commandList.size()] 

    for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++) 
    { 
     char item[strlen((*t).c_str())]; //create character string 
     strcpy(item, (*t).c_str()); //convert from const char to char 
     progArgs[count] = item; 
     count++; 
    } 

编辑:

感谢所有的快速反应大家......我看你说什么

+1

除了其他的东西外,'strlen((* t).c_str())'可以替换为't-> size()'。 – 2010-09-15 02:14:32

回答

3

您正在为每个元素progArgs分配相同的指针(堆栈数组item的第一个元素的地址),然后重复覆盖该内存。你可以这样做:

progArgs[count] = strdup(t->c_str()); 

并摆脱了身体的前两行。

strdup分配内存,所以你将不得不在每个元素后面用free释放。另外,你没有为NUL终结符分配一个字符。您需要strlen + 1.但是,这不是strdup的问题,因为它为您分配。

+0

非常感谢。 – Ryan 2010-09-15 02:15:30

+1

这忽略了commandList将处于作用域并且至少在progArgs被使用之前保持不变的情况,在这种情况下'progArgs [count] = t-> c_str();'就足够了,并且不需要free()。 – 2010-09-15 02:31:53

+0

@Tony:'progArgs [count] = t-> c_str()'是非法的,因为'progArgs'是'char *'的数组,而不是'const char *'的数组。如果这是针对'exec'和朋友的猜测,那么Ryan是其不友好但向后兼容的API的牺牲品。 – 2010-09-15 03:04:44

3

progArgs是指向字符数组。

您将每个指针设置为指向itemitem是循环中的局部变量,因此一旦循环退出,item不再存在,并且指针不再有效[*]。但是,在您的C++实现中,它们仍然指向堆栈上曾经是数组item的内存位。该内存包含上次使用的内容,它是列表中最后一个字符串的字符序列。

如果你想字符串列表复制到一个数组,它会更好,如果可以使用字符串数组:

std::string progArgs[commandList.size()] // if your compiler has C99 VLAs as an extension 
int count = 0; 

for(std::list<std::string>::iterator t=commandList.begin(); t != commandList.end(); ++t) { 
    progArgs[count] = *t; 
    ++count; 
} 

甚至更​​好,用一个向量而不是数组:

std::vector<std::string> progArgs(commandList.begin(), commandList.end()); 

[*]更准确地说,的item范围是循环的一个重复,它的标称“创造”和“破坏”围绕每个时间。但是这并没有做任何工作 - 在你的C++实现中,每次都重用相同的内存区域,并且不需要在堆栈上创建或销毁char数组。

+0

复制到char *数组对于调用期望它的C API非常有用,例如UNIX/Linux execv(...),execvp()。 – 2010-09-15 02:30:28

+0

@Tony:是的,虽然这并不排除使用'vector '来存储复制的字符串数据。也就是说,如果'char *'数组仅用于对exec的调用,然后立即丢弃,我认为根本不需要复制字符串。 'exec'函数实际上并不修改字符串数据,由于历史的原因,它们只取非const,所以对于这个用法,你可以''const_cast''c_str()'的结果。我想,只是为了避免复制一些字符串有点棘手。 – 2010-09-15 02:52:25

+0

我想'在执行'的情况下,你不需要释放内存,因为进程即将被替换,所以有关RAII的良好实践是无关紧要的...... – 2010-09-15 03:01:06

0

您每次都将progArgs[count]设置为相同的项目!

int count = 0; 
char *progArgs[commandList.size()] 

for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++) 
{ 
    char * item = new char[strlen((*t).c_str()) + 1]; //create new character string 
    strcpy(item, (*t).c_str()); //convert from const char to char 
    progArgs[count] = item; 
    count++; 
} 

然后记得要为progArgs中的每个元素调用delete[]

就我个人而言,我会创建一个string的数组,并根据需要随时转换为char *

0

char数组item是局部变量,仅在for循环内可用。

改为动态分配它。

0

你说得对:

for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++) 
{ 
    char item[strlen((*t).c_str())]; //create character string 

...这并创建一个数组,但它会创建它在堆栈上,所以当你到达其范围的结束,它就会被销毁。

strcpy(item, (*t).c_str()); //convert from const char to char 
    progArgs[count] = item; 
    count++; 
} 

......并且这个右大括号表示其范围的结束。这意味着你正在创建一个字符串,将它放入你的数组中,然后在添加下一个之前销毁它。由于你在堆栈中创建它们,所创建的每个新创建的目标都与上一个创建的完全相同,所以毫不奇怪,在最后,你会有一堆相同的字符串

如果你告诉我们你想在这里完成什么,也许会更好,所以我们可以帮你做到这一点。

1

item具有本地循环范围。因此,propArgs数组包含一堆基于堆栈的指针,可能都是一样的。你可以在调试器中检查它是如何工作的,只需循环两次,应该清楚发生了什么。

当您退出循环时,由公共指针寻址的缓冲区包含最近复制的c_str()

你可以通过做

char* item = new char[strlen((*t).c_str()) + 1]; 

解决这个问题,但是,你不得不在退出循环删除[]所有propArgs数组项。

此代码显示了对内存管理的基本缺乏理解,因此在重构代码之前进一步阅读可能会有用。如果这里使用的代码只比这个例子稍微复杂一些,那么它可能只会崩溃,因为在循环外部任何访问propArgs都将依赖于无效(不在范围内)item

+0

您的建议修补程序与原始修补程序一样有一个脱机。 – 2010-09-15 02:14:49

+0

@Matthew - 谢谢,修正 – 2010-09-15 11:16:42