自写C函数拆分字符串时出错
几周前我刚刚学习了字符串,我对自己的函数很感兴趣。起初我试了一个短句,效果不错,但当我试了一个长句时遇到了一个问题 问题可能在“getSplitText”函数中,如何修复此错误 在这种情况下使用for循环是否不好 以前 之后 这是我的密码自写C函数拆分字符串时出错,c,string,loops,C,String,Loops,几周前我刚刚学习了字符串,我对自己的函数很感兴趣。起初我试了一个短句,效果不错,但当我试了一个长句时遇到了一个问题 问题可能在“getSplitText”函数中,如何修复此错误 在这种情况下使用for循环是否不好 以前 之后 这是我的密码 #include <stdio.h> #include <stdlib.h> char *getSplitText(char *var_text, char split, int index); int getLengthSpli
#include <stdio.h>
#include <stdlib.h>
char *getSplitText(char *var_text, char split, int index);
int getLengthSplitText(char *var_text, char split);
int getLengthString(char *var_text);
int main(){
char var_text[100];
fgets(var_text,100,stdin);
int i;
printf("Total Characters: %d\n",getLengthString(var_text));
printf("Total Words: %d\n",getLengthSplitText(var_text,' '));
printf("Split Result:\n");
for(i=1;i<=getLengthSplitText(var_text,' ');i++){
printf("#%d-%s\n",i,getSplitText(var_text,' ',i));
}
return 0;
}
int getLengthString(char *var_text){
int len = 0, i = 0;
while (var_text[i] != '\0'){
len++;
i++;
}
return len;
}
int getLengthSplitText(char *var_text, char split){
int textlen = getLengthString(var_text);
int lenKata=0;
char *resultKata = malloc(sizeof(char) * textlen);
resultKata[0]='\0';
int i,j=0;
for(i=0;i<textlen;i++){
if(var_text[i]!=split){
if(textlen-1==i){
resultKata[j] = var_text[i];
resultKata[j + 1] = '\0';
lenKata ++;
}else {
resultKata[j] = var_text[i];
j++;
resultKata[j + 1] = '\0';
}
//printf("#1 %s\n",resultKata);
}else if(var_text[i]==split){
if(resultKata[0]!='\0'){
lenKata ++;
}else{
j = 0;
resultKata[0] = '\0';
}
}
//printf("#2 %s\n",resultKata);
}
return lenKata;
}
char *getSplitText(char *var_text,char split, int index){
int textlen = getLengthString(var_text);
char *resultKata = malloc(sizeof(char) * textlen);
resultKata[0]='\0';
if(index<=getLengthSplitText(var_text,split)) {
int i,j=0;
int lenKata=0;
for (i = 0; i < textlen; i++) {
if (var_text[i] != split) {
if (textlen - 1 == i) {
resultKata[j] = var_text[i];
resultKata[j + 1] = '\0';
lenKata++;
break;
} else {
resultKata[j] = var_text[i];
j++;
resultKata[j + 1] = '\0';
}
//printf("#1 %s\n",resultKata);
} else if (var_text[i] == split) {
if (resultKata[0] != '\0') {
lenKata++;
if (lenKata == index) {
resultKata[j] = '\0';
break;
} else {
j = 0;
resultKata[0] = '\0';
}
}
//printf("#2 %s\n",resultKata);
}
}
}
return resultKata;
}
#包括
#包括
char*getSplitText(char*var_text,char split,int index);
int getLengthSplitText(char*var_text,char split);
int getLengthString(字符*var_文本);
int main(){
char var_text[100];
fgets(变量文本,100,标准文本);
int i;
printf(“总字符数:%d\n”,getLengthString(var_text));
printf(“总字数:%d\n”,getLengthSplitText(var_text,”);
printf(“分割结果:\n”);
对于(i=1;i在OP的代码中出现了大量的malloc()
关于已经提出的意见:
将任何值乘以1都没有效果,只会使代码变得混乱。建议删除该表达式
嗯,这是风格的问题。如果它提高或削弱代码的可读性是个人喜好的问题。我假设编译器足够聪明,可以忽略1的乘法,我也会忽略
函数:malloc()
需要类型为:size\u t
的参数,但textlen
声明为int
虽然我同意,但只要提供的int
值为正值,我不认为这是一个临界点
始终检查(!=NULL)返回值以确保操作成功
这也是我的建议
我个人感到恼火的是,代码中有一些malloc()
s,但没有一个free()
。使用malloc()
分配内存意味着,一些堆内存在内部堆内存管理器中被标记为“正在使用”。如果它不是free()
d,它将被标记为“已使用”直到进程生命周期结束。丢失(例如重写)指向已分配内存的指针会使其丢失。(无法再次寻址)。这称为
当然,在公开的示例代码中,这并不是一个关键问题,但在堆内存消耗较多的大型应用程序中,它可能会成为一个关键问题
整个示例似乎类似于使用标准库函数可以完成的操作
(并不是说你误解了我的意思。我不认为出于学习目的而与标准函数相似有什么不好的地方。)
getLengthString()
实际上没有什么问题。但是,它管理两个计数变量i
和len
。OP可能忽略了它们在每个迭代步骤后始终具有相同的值。因此,其中一个是冗余的,可以消除:
int getLengthString(char *var_text)
{
int len = 0;
while (var_text[len]) ++len;
return len;
}
关于getLengthSplitText()
(负责计算单词数),我不明白为什么需要任何malloc()
。因此,我编写了一个新函数getNumTokens()
,它计算由某个拆分字符分隔的非空单词(我称它们为“标记”):
int getNumTokens(char *var_text, char split)
{
int n = 0;
for (int inToken = 0; *var_text; ++var_text) {
if (!inToken && *var_text != split) ++n; // count if new token starts
inToken = *var_text != split; // update flag
}
return n;
}
它有点短,不需要任何malloc()
请注意变量inToken
,它实际上用作(布尔)标志。它负责记住在对文本进行迭代时是否已对令牌进行计数。它在每个迭代步骤中都会通过指定当前字符(*var_text
)和分隔符(split
)的比较结果进行更新
提供的var_text
直接用于访问和进度–不使用额外的索引。由于只需要对文本进行一次迭代,因此更改指针不会造成任何影响。它是一个本地副本(按值传递),函数内部的生存时间有限
关于strtok()
,我曾经写过一个变体作为答案
有两个事实需要注意:
strtok()
通过将分隔符替换为\0
字节来修改输入字符串(以分隔找到的标记)
strtok()
管理使其不可重入的内部全局状态
通过使用malloc()
(考虑到上面提到的所有问题),OP的解决方案似乎没有这些限制
所以,我稍微改变了一些假设(实际上OPs问题中没有提到限制)。我认为对输入(1)的修改是可以接受的,并编写了一个新函数getNextToken()
:
函数将返回var\u text
中第一个标记的开头。如果它是空字符串(返回指针的内容是\0
),则找不到任何标记。
因此,找到标记的结尾用\0
-字节(在给定的输入字符串中)表示,该字节可能是之前的拆分字符
由于我不想要全局内部状态,我必须在getNextToken()
之外从一个令牌移动到另一个令牌。我发现这是可以接受的,因为可以再次使用函数getLengthString()
来完成。这样,指针就可以从令牌的开始移动到结束处(写入了\0
-字节)。添加1,则到达下一个令牌的可能开始。当然,当到达文本结尾时,这可能会中断(终止符\0
后面的地址可能超出范围)。幸运的是,令牌的数量已经已知
完整样本:
#include <stdio.h>
int getLengthString(char *var_text);
int getNumTokens(char *var_text, char split);
char* getNextToken(char *var_text, char split);
int main()
{
char var_text[100];
if (!fgets(var_text, 100, stdin)) {
fprintf(stderr, "Input failed!\n");
return -1;
}
printf("Total Characters: %d\n", (int)getLengthString(var_text));
const char split = ' ';
const int nTokens = getNumTokens(var_text, split);
printf("Total Words: %d\n", nTokens);
printf("Split Result:\n");
char *token = var_text;
for (int i = 1; i <= nTokens; ++i) {
token = getNextToken(token, split);
printf("#%2d-%s\n", i, token);
token += getLengthString(token) + 1;
}
return 0;
}
int getLengthString(char *var_text)
{
int len = 0;
while (var_text[len]) ++len;
return len;
}
int getNumTokens(char *var_text, char split)
{
int n = 0;
for (int inToken = 0; *var_text; ++var_text) {
if (!inToken && *var_text != split) ++n; // count if new token starts
inToken = *var_text != split; // update flag
}
return n;
}
char* getNextToken(char *var_text, char split)
{
// skip space
for (; *var_text && *var_text == split; ++var_text);
// remember start of token
char *token = var_text;
// skip token
for (; *var_text && *var_text != split; ++var_text);
// remark end of token
*var_text = '\0'; // doesn't hurt if there is already a '\0'
// done
return token;
}
的输出谢谢您的帮助。现在,代码可以工作了。我喜欢编程。
:
字符总数:68
字总数:13
拆分结果:
#1-谢谢
#2-you
#3人
#4-1
#5-help。
#6-现在,
#7-1
#8码
#9罐
#10-w
#include <stdio.h>
int getLengthString(char *var_text);
int getNumTokens(char *var_text, char split);
char* getNextToken(char *var_text, char split);
int main()
{
char var_text[100];
if (!fgets(var_text, 100, stdin)) {
fprintf(stderr, "Input failed!\n");
return -1;
}
printf("Total Characters: %d\n", (int)getLengthString(var_text));
const char split = ' ';
const int nTokens = getNumTokens(var_text, split);
printf("Total Words: %d\n", nTokens);
printf("Split Result:\n");
char *token = var_text;
for (int i = 1; i <= nTokens; ++i) {
token = getNextToken(token, split);
printf("#%2d-%s\n", i, token);
token += getLengthString(token) + 1;
}
return 0;
}
int getLengthString(char *var_text)
{
int len = 0;
while (var_text[len]) ++len;
return len;
}
int getNumTokens(char *var_text, char split)
{
int n = 0;
for (int inToken = 0; *var_text; ++var_text) {
if (!inToken && *var_text != split) ++n; // count if new token starts
inToken = *var_text != split; // update flag
}
return n;
}
char* getNextToken(char *var_text, char split)
{
// skip space
for (; *var_text && *var_text == split; ++var_text);
// remember start of token
char *token = var_text;
// skip token
for (; *var_text && *var_text != split; ++var_text);
// remark end of token
*var_text = '\0'; // doesn't hurt if there is already a '\0'
// done
return token;
}