循环的C参考
我的C代码有问题循环的C参考,c,loops,pointers,for-loop,C,Loops,Pointers,For Loop,我的C代码有问题 int split(char* source, char*** target, char* splitChar) { int i; int currentLength; int splitCharPosition; char* currentSubstring = source; int splitCount = charcount(source, splitChar) + 1; *target = (char**) mallo
int split(char* source, char*** target, char* splitChar) {
int i;
int currentLength;
int splitCharPosition;
char* currentSubstring = source;
int splitCount = charcount(source, splitChar) + 1;
*target = (char**) malloc(splitCount * sizeof(char**));
for(i=0;i<splitCount;i++) {
splitCharPosition = indexOf(currentSubstring, splitChar);
substring(currentSubstring, target[i], 0, splitCharPosition);
currentLength = strlen(currentSubstring);
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
}
return splitCount;
}
编辑2:
int charcount(char* source, const char* countChar) {
int i;
int count = 0;
for(i=0;source[i];i++) {
if(source[i] == countChar[0]) {
count++;
}
}
return count;
}
编辑3:
char* substring(char* source, char** target, int start, int length) {
*target = (char*) malloc(length + 1);
strncpy(*target, source + start, length);
target[length] = '\0';
return *target;
}
编辑4:
我只是注意到如果我加上
char* sndfpgjps = splitChar;
对于我的split()代码,它不会删除引用。有人知道为什么吗?看看您的调试器是否也支持数据断点,即,如果内存中的某个位置被修改,就会中断。然后将一个放在splitChar的实际地址,另一个放在它指向的地址。(因为您没有指定指针是null还是指向nil。)查看它在哪里中断。这可能是一个完全无关的地方;这表示缓冲区溢出
此外,您至少可以使splitChar成为指向常量的指针。你其实不想修改它,对吧?更好的办法是,将其设置为字符,而不是指针,因为其名称表明只有一个字符可以拆分,而不是字符串。对
子字符串的第一次调用看起来不正确:
substring(currentSubstring, target[i], 0, splitCharPosition);
我猜想它应该是如下所示,其中它对分配的实际内存进行了索引:
substring(currentSubstring, &((*target)[i]), 0, splitCharPosition);
首先需要获取目标指向的值(*target
),然后从中索引并传递该数组位置的地址。我不知道子字符串是什么,也不知道它有什么签名,但在行中
substring(currentSubstring, target[i], 0, splitCharPosition);
仅为i==0定义了目标[i]。我相信你想写作
substring(currentSubstring, (*target)[i], 0, splitCharPosition);
这一行:-
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
。。。将导致内存泄漏,并且效率极低。旧的子字符串悬空。永远也不会自由
最好是写
currentSubString += splitCharPosition + 1;
我不认为这是个问题,但这是个问题
另外,当您使用C库函数时,比如strlen()
,为什么不使用strtok
,或者更好的是,strtok\u r
?我对代码有一些保留,但这在valgrind
下可以正常工作(没有泄漏,没有滥用)。除了常量字符串被标记为常量之外,我基本上没有改变子函数。split()
中的代码已简化。正如我在评论中所指出的,我建议编写mainsplit()
函数,这样您就有了一个本地char**string\u列表代码>您分配和填充的代码。然后,当您准备返回时,分配*target=string\u list代码>。这将使你更容易理解正在发生的事情。三重间接是讨厌的。您可以在这里证明这一点(仅此而已),但要尽可能减少使用三点指针的时间。修订采用了这一战略
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
然后,您可以将指向其中一个的指针传递到split()
,并传递到诸如free\u list()
和print\u list()
等实用程序函数中。然后,free_list()
函数将修改结构,以便在释放结构指向的数据后,两个元素都归零
我还想使用不同的indexOf()
实现:
在这里发布您的问题之前,您提到您使用了调试器,因此您获得了一张赞成票。这可能只是我的问题,但我觉得这段代码对于它试图实现的目标来说过于复杂。您触摸splitChar的唯一位置是在indexOf()
中,所以请先查看(或显示函数)splitChar
也被传递到charcount()
,所以也给我们展示一下这个函数。char***target
在我看来是一个非常糟糕的气味。用const尝试过,但仍然不起作用。名称可能选错了,我还想在字符串上拆分。你是对的。这就是我想做的。但不幸的是,这并不能解决我的问题。这是对一个问题的正确诊断。我建议编写mainsplit()
函数,这样您就有了一个本地char**string\u列表代码>您分配和填充的代码。然后,当您准备返回时,分配*target=string\u list代码>。这将使你更容易理解正在发生的事情。三重间接是讨厌的。您可以在这里证明这一点(仅此而已),但要尽可能减少使用三点指针的时间,如图所示。您是对的。这就是我想做的。但不幸的是,这并不能解决我的问题。是否有一个C库函数可以在字符串上拆分给定的字符串?标准C库中没有一个函数可以根据您想要的分隔符字符串拆分字符串。最接近的方法是strtok()
函数,但它会在单个字符的任意选择上进行拆分,而不是在字符串上进行拆分(还有许多其他问题-如果可以,请避免strtok()
;如果不能,请使用strtok\u r()
或strtok\u s()
)。一个原因是标准C库几乎在所有地方都避免了内存分配(当然除了malloc()
、realloc()
、calloc()
和free()
)。TR 24731-2将改变这一点;它没有被采纳到C2011中。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
typedef struct StringList
{
size_t nstrings;
char **strings;
} StringList;
int indexOf(const char *haystack, const char *needle)
{
const char *pos = strstr(haystack, needle);
if (pos != 0)
return (pos - haystack);
return -1;
}