【问题标题】:Creating a function to allocate a array of strings in C在 C 中创建一个函数来分配字符串数组
【发布时间】:2021-10-07 08:14:37
【问题描述】:

我正在使用 C 语言编写 minisql 代码,但在分配字符串数组时遇到了一些问题。我创建了一个名为“alocaString”的函数来执行此操作(bc 我经常使用它),但我认为它不起作用。 当代码到达“strncpy(lista[qtnPalavras], splitStr, 100);”行时在函数“listaPalavras”(用于将字符串拆分为不同类型的字符)中,创建了一个名为“strcpy-avx2.S”的文件,该函数的一个参数(**lista)分配有“ alocaString" 所以我认为问题出在那个函数上。

我已经尝试使用 valgrind 并向我尝试在该函数上使用的所有字符串数组显示“在此函数中未初始化 [-Werror=uninitialized]”,但我在函数内部初始化它们

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;
}

【问题讨论】:

  • 并且由于您要覆盖参数char **string,因此最好作为局部变量而不是参数。
  • @user3121023 我更改为 char **alocaString,现在我遇到了另一个问题。当我运行代码时,它在释放内存时显示“free():无效指针”

标签: c malloc


【解决方案1】:

我假设你是这样使用这些函数的:

alocaString(lista, tamanho, posicoes);
listaPalavras(some_string, lista, some_delimiters);
desalocaString(arr);

即使不查看代码,如果您还不知道它需要容纳多少个字符串,那么先分配一个字符串数组然后填充它似乎在逻辑上是错误的。如果您碰巧分配了一个n 字符串数组,但您的listaPalavras() 函数将提供的字符串拆分为n+1 或更多子字符串,那么您将溢出先前分配的数组。尽管如此,这可以通过采取适当的预防措施来完成,例如随身携带尺寸并检查它们以避免溢出。

因此,实现您想要的唯一明智的方法是(A)首先计算字符串中的定界符数量以有利地知道您需要多少指针或(B)在@987654325中动态分配所需的数量@同时分裂。您似乎正在使用类似于选项 A 的内容,但您的代码有缺陷。

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(),它负责将给定字符串拆分为其他字符串并将它们复制到先前分配的数组中,以避免溢出给定的字符串数组,您还需要提供其长度以及先前分配的字符串的长度作为参数(让我们称它们为posicoestamanho,就像上面的函数一样)。此外,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);

这应该可以正常工作,但是您会受到以下事实的限制:

  1. 您无法事先知道strtok() 将找到的子字符串的数量。
  2. 您无法事先知道任何这些子字符串的长度。

因此,在listaPalavras() 中动态分配所需的lista 会更有意义。

最后,作为旁注,您的函数名称具有误导性:如果您需要分配一个字符串数组,您可能希望选择一个比 alocaString() 更好的名称,这似乎暗示您正在分配一个 单个字符串。也许alocaLista()dealocaLista() 会是更好的选择。

【讨论】:

  • @mebeim 我试过了,但它给出了另一个问题,它创建了一个名为“strlen-avx2.S”的文件
  • @BeatrizCardoso 你必须比这更具体。更新您的问题,添加您如何编译和执行程序以及任何步骤的输出。
猜你喜欢
  • 2012-06-19
  • 2020-09-08
  • 1970-01-01
  • 2020-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
相关资源
最近更新 更多