【发布时间】:2019-03-25 23:11:55
【问题描述】:
我的str_split 函数返回(或者至少我认为是这样)char** - 所以本质上是一个字符串列表。它需要一个字符串参数、一个 char 分隔符来分割字符串,以及一个指向 int 的指针来放置检测到的字符串数。
我这样做的方式可能非常低效,是创建一个 x 长度的缓冲区(x = 字符串长度),然后复制字符串的元素,直到我们到达分隔符或 '\0' 字符。然后它将缓冲区复制到char**,这就是我们要返回的内容(之前已经被malloced,并且可以从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;
}
【问题讨论】:
-
"然后它将缓冲区复制到 char**" - 不,它没有。在哪里?
-
在:ret[c] = 缓冲区;我错过了一些非常明显的东西吗?对不起!编辑:如果您指的是副本的使用,我可以互换使用“副本”和“设置”。就像设置 char**[index] 的值等于缓冲区一样。
-
这不会复制缓冲区。
ret[c]只是一个指针。您将它设置为指向buffer,这是一个局部变量,当周围的函数返回时它会被销毁。此外,ret的所有元素都具有相同的值 (buffer)。您正在返回一个包含相同垃圾指针的数组。 -
您正在存储指向堆栈中存在的缓冲区的指针。从函数返回后使用这些指针会导致未定义的行为。
-
@melpomene 啊!我想它是那样的,但我无法用我的一生来形容它。非常感谢先生。那么你会如何建议我从这里开始 - 有没有其他方法可以分别 malloc'ing 每个字符串?当然,我永远无法释放他们。
标签: c arrays pointers split malloc