C运行时错误中的拆分函数
我在运行C程序时遇到运行时错误, 以下是C源代码(解析略低一点的.h头代码): 提前谢谢,我没有全部编程,只是从一些地方取了一些片段,但大部分是我的编程,谢谢 该函数的目的是,如果作为参数传递的条件为false,它将停止程序。这告诉您,当您运行程序时,C运行时错误中的拆分函数,c,pointers,C,Pointers,我在运行C程序时遇到运行时错误, 以下是C源代码(解析略低一点的.h头代码): 提前谢谢,我没有全部编程,只是从一些地方取了一些片段,但大部分是我的编程,谢谢 该函数的目的是,如果作为参数传递的条件为false,它将停止程序。这告诉您,当您运行程序时,idx!=第69行计数-1。我没有花时间检查程序执行时的导入,但显然(?)idx的目的是在那里等于count-1 这有用吗?有很多问题。我忽略了分为两个文件的代码;我将其视为一个单独的文件(请参见问题的注释) 不要使用get()。切勿使用get()
idx!=第69行计数-1
。我没有花时间检查程序执行时的导入,但显然(?)idx
的目的是在那里等于count-1
这有用吗?有很多问题。我忽略了分为两个文件的代码;我将其视为一个单独的文件(请参见问题的注释)
get()
。切勿使用get()
。永远不要使用get()
。我说了三遍;这一定是真的。请注意,gets()
不再是标准的C函数(它已从C11标准ISO/IEC 9899:2011中删除),因为它不能安全使用。改用fgets()
或其他安全函数main()
末尾的所有子字符串,从而导致内存泄漏Split()。strtok()
函数具有破坏性。它还将多个相邻分隔符视为单个分隔符。您的代码无法解释差异
Split()
函数中的分隔符分析字符串,但使用strtok(…,',')
来实际拆分逗号。这与评论和名字更为一致,但完全误导了你。这就是您的断言被激发的原因
,除非您正在使用它提供的额外设施。你不是,所以你不应该包括它
完美地声明了malloc()
和free()
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int altSplitLen(char **array);
static char **Split(char *a_str, const char a_delim);
static int SplitLen(char *src, char sep);
int main(void)
{
printf("Enter text separated by single spaces:\n");
char a[4096]; // Simpler
if (fgets(a, sizeof(a), stdin) != 0) // Error checked!
{
char **aa = Split(a, ' ');
int k = SplitLen(a, ' ');
printf("SplitLen() says %d; altSplitLen() says %d\n", k, altSplitLen(aa));
for (int i = 0; i < k; i++)
{
printf("%s\n", aa[i]);
}
/* Workaround for broken SplitLen() */
{
puts("Loop to null pointer:");
char **data = aa;
while (*data != 0)
printf("[%s]\n", *data++);
}
{
// Fix for major leak!
char **data = aa;
while (*data != 0)
free(*data++);
}
free(aa); // Major leak!
}
return 0;
}
char **Split(char *a_str, const char a_delim)
{
char **result = 0;
size_t count = 0;
char *tmp = a_str;
char *last_comma = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char *) * count);
if (result)
{
char delim[2] = { a_delim, '\0' }; // Fix for inconsistent splitting
size_t idx = 0;
char *token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
int SplitLen(char *src, char sep)
{
int result = 0;
for (size_t i = 0; i < strlen(src); i++)
{
if (src[i] == sep)
{
result += 1;
}
}
return result;
}
static int altSplitLen(char **array)
{
int i = 0;
while (*array++ != 0)
i++;
return i;
}
请注意,
fgets()
保留换行符,而gets()
不保留,因此换行符包含在输出中。还要注意printf()
打印数据如何显示字符串的限制;这在很多情况下都非常有用。欢迎使用堆栈溢出。请尽快阅读这一页。使用malloc()
分配10个字节非常小(例如,使用4096),并且没有什么意义(局部变量更简单)。然后使用gets()
读取数据是一场灾难-决不,决不,决不,决不使用gets()
!(它不再是标准C11的一部分。)甚至在玩具程序中也没有。你会因为使用断言而得到一些补偿。您需要学习如何使用调试器,或者如何插入打印语句,以便为您提供查看出错原因所需的信息。您听说过调试器吗?这将比发布大量代码还要快,同时,头文件通常不应该包含函数定义;当它们这样做时,它们应该是静态内联
函数。将声明放在头文件(parsing.h
)中,将定义放在单独的源文件(parsing.c
)中,分别编译主程序文件和parsing.c
文件,并将它们链接在一起。虽然在这种情况下您可以不受影响,但您所做的事情是不可伸缩的(只要有多个源文件需要使用这些函数,您就处于失败的境地)。我现在使用的是scanf(),没有错误,但没有显示任何内容。@JonathanLeffler,所以您现在(希望也是这样)理解我的沮丧;-)任何C编译器都不能混淆assert
中的表达式。如果它确实被弄糊涂了,它就不是一个C编译器。括号是不必要的。如果我对断言行进行注释,那么在它打印两个值之后就会出现分段错误,但我隐藏了一点Split()代码,所以我不太清楚它是如何工作的,我希望很快能阅读关于这个主题的教程。谢谢你对这个问题的见解。@JonathanLeffler好的,谢谢!我现在删除了答案的这一部分。非常感谢!,它起作用了,我本可以给你的答案打分,但我只有1分:(.无论如何,谢谢你:):)唯一的问题是你在for循环中使用了decelleration,我的编译器不是C99:)好奇:你的代码在char*a=malloc(10)之前有一个printf()
语句代码>,所以我认为它是安全的-似乎您必须使用C99编译器才能使其合法。然而,也许你在Windows上使用MSVC。在这种情况下,你必须移动一些东西,但是变化很小。如果您使用的编译器只支持20多年前的标准,而不是10多年前的标准或几年前的标准,那么有必要指出这一点(或者至少提及这一点)。大多数公司都会设法解决问题,使它们不会过时20年。我使用的是带GCC的linux。或者在“软呢帽”上。所以这很奇怪。
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
char** Split(char* a_str, const char a_delim)
{
char** result = 0;
int count = 0;
char* tmp = a_str;
char* last_comma = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char*) * count);
if (result)
{
size_t idx = 0;
char* token = strtok(a_str, ",");
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, ",");
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
int SplitLen(char *src, char sep)
{
int result = 0;
int i;
for(i = 0; i<strlen(src); i++)
{
if(src[i] == sep)
{
result += 1;
}
}
return result;
}
a.out: parsing.h:69: Split: Assertion `idx == count - 1' failed.
Aborted
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int altSplitLen(char **array);
static char **Split(char *a_str, const char a_delim);
static int SplitLen(char *src, char sep);
int main(void)
{
printf("Enter text separated by single spaces:\n");
char a[4096]; // Simpler
if (fgets(a, sizeof(a), stdin) != 0) // Error checked!
{
char **aa = Split(a, ' ');
int k = SplitLen(a, ' ');
printf("SplitLen() says %d; altSplitLen() says %d\n", k, altSplitLen(aa));
for (int i = 0; i < k; i++)
{
printf("%s\n", aa[i]);
}
/* Workaround for broken SplitLen() */
{
puts("Loop to null pointer:");
char **data = aa;
while (*data != 0)
printf("[%s]\n", *data++);
}
{
// Fix for major leak!
char **data = aa;
while (*data != 0)
free(*data++);
}
free(aa); // Major leak!
}
return 0;
}
char **Split(char *a_str, const char a_delim)
{
char **result = 0;
size_t count = 0;
char *tmp = a_str;
char *last_comma = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char *) * count);
if (result)
{
char delim[2] = { a_delim, '\0' }; // Fix for inconsistent splitting
size_t idx = 0;
char *token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
int SplitLen(char *src, char sep)
{
int result = 0;
for (size_t i = 0; i < strlen(src); i++)
{
if (src[i] == sep)
{
result += 1;
}
}
return result;
}
static int altSplitLen(char **array)
{
int i = 0;
while (*array++ != 0)
i++;
return i;
}
$ parsing
Enter text separated by single spaces:
a b c d e f gg hhh iii jjjj exculpatory evidence
SplitLen() says 0; altSplitLen() says 12
Loop to null pointer:
[a]
[b]
[c]
[d]
[e]
[f]
[gg]
[hhh]
[iii]
[jjjj]
[exculpatory]
[evidence
]
$