我正在用 C 编写 minisql 代码,但在分配字符串数组时遇到了一些问题。我制作了一个名为“alocaString”的函数来执行此操作(bc 我经常使用它),但我认为它不起作用。 当代码到达“strncpy(lista[qtnPalavras], splitStr, 100);”这一行时在函数“listaPalavras”(目的是将字符串拆分为不同类型的字符)中,创建了一个名为“strcpy-avx2.S”的文件,该函数(**lista)的参数之一被分配了“ alocaString”,所以我认为问题出在该函数中。
我已经尝试使用 valgrind 并向我尝试在该函数上使用的所有字符串数组显示“在此函数中未初始化使用 [-Werror=uninitialized]”,但我正在函数内部初始化它们< /p>
int alocaString (char **string, int tamanho, int posicoes){
string = malloc (posicoes * sizeof(char*));
for (int i = 0; i < posicoes; i++){
string [i] = malloc (tamanho * sizeof(char));
if (string[i] == NULL){return 0;}
}
return **string;
}
void desalocaString (char **string, int posicoes){
for (int i = 0; i < (posicoes); i++){
free (string[i]);
}
free (string);
}
int listaPalavras(char *entrada, char **lista, char *separador){ // lista as palavras
char *splitStr;
int qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, 100);
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
答案 0 :(得分:1)
我假设您正在使用这些函数:
alocaString(lista, tamanho, posicoes);
listaPalavras(some_string, lista, some_delimiters);
desalocaString(arr);
即使不看代码,如果您还不知道需要容纳多少个字符串,那么先分配一个字符串数组然后再填充它在逻辑上似乎是错误的。如果您碰巧分配了一个 n
字符串数组,但您的 listaPalavras()
函数将提供的字符串拆分为 n+1
或更多子字符串,那么您将溢出之前分配的数组。尽管如此,这可以通过采取适当的预防措施来完成,例如随身携带尺寸并检查它们以避免溢出。
因此,实现您想要的唯一明智的方法是(A)首先计算字符串中的分隔符数量,以便有利地知道您将需要多少个指针,或者(B)在 {{ 1}} 分裂时。您似乎采用了类似于选项 A 的方法,但您的代码存在缺陷。
listaPalavras()
是唯一看起来正确的函数。
desalocaString()
的正确实现将返回分配的数组(或在失败的情况下返回 alocaString()
),但您返回的只是 NULL
第一个字符串的第一个字符。不用说,这没有多大意义。您不需要采用 **string
参数,只需采用尺寸即可。其次,如果对 char **
的任何调用失败,您应该在返回 malloc()
之前释放先前分配的调用。
NULL
根据char **alocaString (unsigned tamanho, unsigned posicoes) {
char **lista = malloc(posicoes * sizeof(char*));
if (lista == NULL)
return NULL;
for (unsigned i = 0; i < posicoes; i++) {
lista[i] = malloc(tamanho * sizeof(char));
if (lista[i] == NULL) {
for (unsigned j = 0; j < i; j++)
free(lista[j]);
free(lista);
return NULL;
}
}
return lista;
}
,它负责将给定的字符串拆分为其他字符串并将它们复制到先前分配的数组中,以避免溢出给定的字符串数组,您还需要提供其长度作为先前分配的字符串的长度作为参数(让我们像上面的函数一样称它们为 listaPalavras()
和 posicoes
)。此外,如果在源字符串的前 tamanho
个字符内找不到目标字符串,strncpy()
将不向目标字符串添加 NUL 终止符 (\0
) (n
是第三个参数),因此您需要自己添加它以确保您的字符串正确终止。
n
最后调用者的代码应该是这样的:
unsigned listaPalavras(const char *entrada, char *separador, char **lista, unsigned posicoes, unsigned tamanho) {
char *splitStr;
unsigned qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (qtnPalavras < posicoes && splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, tamanho);
lista[qtnPalavras][tamanho - 1] = '\0';
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
这应该可以正常工作,但是您受到以下事实的限制:
char **lista;
unsigned tamanho = 100;
unsigned posicoes = 10;
unsigned palavras;
lista = alocaString(tamanho, posicoes);
if (lista == NULL) {
// handle the error somehow
}
palavras = listaPalavras(YOUR_STRING, YOUR_DELIMITERS, lista, posicoes, tamanho);
desalocaString(lista);
将找到的子字符串数量。因此,在 strtok()
内动态分配所需的 lista
会更有意义。
最后,作为旁注,您的函数名称具有误导性:如果您需要分配一个字符串数组,您可能想要选择一个比 listaPalavras()
更好的名称,这似乎暗示您正在分配单个字符串。也许 alocaString()
和 alocaLista()
会是更好的选择。