gpt4 book ai didi

c - 为什么我的 string_split 实现不起作用?

转载 作者:太空宇宙 更新时间:2023-11-03 23:58:27 26 4
gpt4 key购买 nike

我的 str_split 函数返回(或者至少我认为它返回)一个 char** - 所以本质上是一个字符串列表。它需要一个字符串参数、一个用于拆分字符串的 char 分隔符和一个指向 int 的指针以放置检测到的字符串数。

我这样做的方法可能非常低效,它是创建一个 x 长度的缓冲区(x = 字符串的长度),然后复制字符串的元素直到我们到达定界符,或者 '\0' 字符。然后它将缓冲区复制到 char**,这就是我们要返回的内容(并且之前已经过 malloc,并且可以从 main() 中释放),然后清除缓冲区并重复。

虽然算法可能有问题,但逻辑绝对正确,因为我的调试代码 (_D) 显示它被正确复制。我坚持的部分是当我在 main 中创建一个 char** 时,将它设置为等于我的函数。它不会返回 null、使程序崩溃或抛出任何错误,但它似乎也不太有效。我假设这就是术语“未定义行为”的含义。

无论如何,经过深思熟虑(我对这一切都是新手)我尝试了一些其他的东西,你会在代码中看到,目前被注释掉了。当我使用 malloc 将缓冲区复制到一个新字符串,并将该副本传递给上述 char** 时,它似乎工作得很好。但是,这会造成明显的内存泄漏,因为我以后无法释放它……所以我迷路了。

当我做一些研究时,我发现了 this post ,它几乎完全遵循我的代码的想法并且有效,这意味着我的 str_split 函数的格式(返回值、参数等)没有固有问题。然而,他只有 1 个 malloc,用于 char**,并且工作正常。

下面是我的代码。我一直在努力解决这个问题,它让我的大脑困惑,所以我真的很感激你的帮助!!提前对“i”、“b”、“c”表示抱歉,我知道这有点令人费解。

编辑:应该用下面的代码提到这一点,

ret[c] = buffer;
printf("Content of ret[%i] = \"%s\" \n", c, ret[c]);

它确实打印正确。只有当我从 main 调用函数时,它才会变得奇怪。我猜这是因为它超出了范围?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEBUG

#ifdef DEBUG
#define _D if (1)
#else
#define _D if (0)
#endif

char **str_split(char[], char, int*);
int count_char(char[], char);

int main(void) {
int num_strings = 0;
char **result = str_split("Helo_World_poopy_pants", '_', &num_strings);

if (result == NULL) {
printf("result is NULL\n");
return 0;
}

if (num_strings > 0) {
for (int i = 0; i < num_strings; i++) {
printf("\"%s\" \n", result[i]);
}
}

free(result);

return 0;
}

char **str_split(char string[], char delim, int *num_strings) {

int num_delim = count_char(string, delim);
*num_strings = num_delim + 1;

if (*num_strings < 2) {
return NULL;
}

//return value
char **ret = malloc((*num_strings) * sizeof(char*));

if (ret == NULL) {
_D printf("ret is null.\n");
return NULL;
}

int slen = strlen(string);
char buffer[slen];

/* b is the buffer index, c is the index for **ret */
int b = 0, c = 0;
for (int i = 0; i < slen + 1; i++) {

char cur = string[i];

if (cur == delim || cur == '\0') {

_D printf("Copying content of buffer to ret[%i]\n", c);
//char *tmp = malloc(sizeof(char) * slen + 1);
//strcpy(tmp, buffer);

//ret[c] = tmp;
ret[c] = buffer;
_D printf("Content of ret[%i] = \"%s\" \n", c, ret[c]);
//free(tmp);

c++;
b = 0;
continue;
}

//otherwise

_D printf("{%i} Copying char[%c] to index [%i] of buffer\n", c, cur, b);

buffer[b] = cur;
buffer[b+1] = '\0'; /* extend the null char */
b++;

_D printf("Buffer is now equal to: \"%s\"\n", buffer);
}

return ret;
}

int count_char(char base[], char c) {
int count = 0;
int i = 0;

while (base[i] != '\0') {
if (base[i++] == c) {
count++;
}
}
_D printf("Found %i occurence(s) of '%c'\n", count, c);
return count;
}

最佳答案

您正在存储指向堆栈上存在的缓冲区的指针。从函数返回后使用这些指针会导致未定义的行为。

要解决此问题,需要执行以下操作之一:

  • 允许函数修改输入字符串(即用空终止符替换定界符)并返回指向它的指针。调用者必须意识到这可能发生。请注意,在这里提供字符串文字在 C 中是非法的,因此您需要这样做:

    char my_string[] = "Helo_World_poopy_pants";
    char **result = str_split(my_string, '_', &num_strings);

    在这种情况下,该函数还应明确表示字符串文字是 Not Acceptable 输入,并将其第一个参数定义为 const char* string(而不是 char string[] ).

  • 允许函数复制字符串,然后修改副本。您已经表达了对泄漏此内存的担忧,但这种担忧主要与您的程序设计有关,而不是必需的。

    单独复制每个字符串然后再将它们全部清理是完全有效的。主要问题是它不方便,而且有点毫无意义。

让我们谈谈第二点。您有多种选择,但如果您坚持要通过调用 free 轻松清除结果,请尝试以下策略:

  1. 分配指针数组时,还要使其足够大以容纳字符串的副本:

    // Allocate storage for `num_strings` pointers, plus a copy of the original string,
    // then copy the string into memory immediately following the pointer storage.
    char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
    char *buffer = (char*)&ret[*num_strings];
    strcpy(buffer, string);
  2. 现在,在buffer 上执行所有字符串操作。例如:

    // Extract all delimited substrings.  Here, buffer will always point at the
    // current substring, and p will search for the delimiter. Once found,
    // the substring is terminated, its pointer appended to the substring array,
    // and then buffer is pointed at the next substring, if any.
    int c = 0;
    for(char *p = buffer; *buffer; ++p)
    {
    if (*p == delim || !*p) {
    char *next = p;
    if (*p) {
    *p = '\0';
    ++next;
    }
    ret[c++] = buffer;
    buffer = next;
    }
    }
  3. 当您需要清理时,只需调用一次 free,因为所有内容都存储在一起。

关于c - 为什么我的 string_split 实现不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55347699/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com