您有许多问题...您的程序当前将表现出未定义的行为,因此在您解决这些问题之前,您无法希望预测正在发生的事情。让我们开始。
以下字符串太短了一个字符。您忘记为字符串终止符 ( '\0'
) 添加一个字符。这将导致标记化期间缓冲区溢出,这可能是您看到的行为的部分原因。
char copy[strlen(commandline)]; // You need to add 1
strcpy(copy, commandline);
下一部分是您的返回值,但它是一个临时的(本地数组)。您不得退货。你应该分配它。
// Don't do this:
char* commands[length];
for (int x=0; x<length; x++)
commands[x] = "\0"; // And this is not the right way to zero a pointer
// Do this instead (calloc will zero your elements):
char ** commands = calloc( length, sizeof(char*) );
标记化循环可能会超出您的缓冲区,因为您从不检查length
,因此您应该添加一个测试:
while( temp != NULL && i < length )
并且由于上述原因,您不能commands[i]
在循环后盲目设置为 NULL 。要么测试,要么i < length
不设置它(无论如何你事先将数组归零)。
现在让我们处理返回值。目前你有这个:
return *commands;
这将返回一个指向临时字符串 ( copy
) 中第一个标记的指针。首先,看起来您实际上打算返回一个令牌数组,而不仅仅是第一个令牌。其次,您不能返回临时字符串。所以,我认为你的意思是:
return commands;
现在,要处理这些字符串......有一个简单的方法,也是一个聪明的方法。已经提出了一种简单的方法:strdup
在将它们推入内存之前调用每个令牌。令人讨厌的部分是,当您清理该内存时,您必须遍历数组并释放每个单独的令牌。
相反,让我们一键完成所有操作,通过一次调用分配数组和字符串存储:
char **commands = malloc( length * sizeof(char*) + strlen(commandline) + 1 );
char *copy = (char*)(commands + length);
strcpy( copy, commandline );
我上面唯一没有做的就是将数组归零。您可以在标记化循环之后执行此操作,只需将剩余值归零即可:
while( i < length ) commands[i++] = NULL;
现在,当您返回时commands
,您会返回一个令牌数组,其中还包含自己的令牌存储。要释放数组及其包含的所有字符串,只需执行以下操作:
free( commands );
把它们放在一起:
void* setCommands(int length)
{
// Create array and string storage in one memory block.
char **commands = malloc( length * sizeof(char*) + strlen(commandline) + 1 );
if( commands == NULL ) return NULL;
char *copy = (char*)(commands + length);
strcpy( copy, commandline );
// Tokenise commands
int i = 0;
char *temp = strtok(copy, " \t");
while( temp != NULL && i < length )
{
commands[i++] = temp;
temp = strtok(NULL, " \t");
}
// Zero any unused tokens
while( i < length ) commands[i++] = NULL;
return commands;
}