读取输入直到C中的分隔符(没有固定的最大长度)
我被要求从用户处读取一个重要符号(分隔符),并将其放入字符串中。我不应该询问需要多少行/字符,也不应该浪费内存空间 最好不要使用C语言中的内置包。我从零开始学习。所以 第一个问题:我应该使用指针还是字符数组?读取输入直到C中的分隔符(没有固定的最大长度),c,C,我被要求从用户处读取一个重要符号(分隔符),并将其放入字符串中。我不应该询问需要多少行/字符,也不应该浪费内存空间 最好不要使用C语言中的内置包。我从零开始学习。所以 第一个问题:我应该使用指针还是字符数组? 请注意,我不知道我要阅读多长时间,我不能浪费内存 以下是我所做的: int main() { char s[100]; int line = 0; int i = 0; printf("type "); printf("\n"); scanf
请注意,我不知道我要阅读多长时间,我不能浪费内存 以下是我所做的:
int main() {
char s[100];
int line = 0;
int i = 0;
printf("type ");
printf("\n");
scanf("%s", &s[i++]);
while (s[i] != '000') {
if (s[i] == '\n') line++;
i++;
scanf("%s", &s[i]);
} //end while
s[i] = '\0';
printf("\n");
printf("lines %d", line);
printf("\n");
int j;
while (s[j] != '\0') {
printf("%s", s[j]);
j++;
}
return 0;
} //end main
您应该将问题重命名为“如何读取未知长度的字符串”。。。 下面是一个这样做的例子。。有稍微更有效的方法,但我尽量保持简单 此代码将从
stdin
读取字符,并将其存储到s
,根据需要分配内存。。最大为任意大小,直到它读取delim
。。设置为一行三个0
字符的字符串,达到EOF(文件结尾)或达到系统内存分配大小的限制
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
char c, *delim = "000";
int i = 0, delimlen = strlen(delim);
/* start out with 2 bytes of memory.. in reality the operating system */
/* will allocate a lot more than that... */
/* using calloc rather than malloc so that memory is initially nulled */
char *s = calloc(2, 1);
/* read characters one at a time from stdin */
while((c = fgetc(stdin)) != EOF) {
/* place character into the next position in the string array.. */
/* and add 1 to i so it indexes the next position in the array */
s[i++] = c;
/* add null terminator */
s[i] = 0;
/* did we get delimiter? */
if(i >= delimlen && !strcmp(s+i-delimlen, delim))
break;
/* increase size of memory s points to, if necessary */
s = realloc(s, i+2);
}
printf("we got input: %s", s);
/* once you are TOTALLY done with s, free the memory so that it can be used again */
free(s);
exit(0);
}
#包括
#包括
#包括
int main(){
字符c,*delim=“000”;
int i=0,delimlen=strlen(delim);
/*从2字节的内存开始..实际上是操作系统*/
/*将分配更多的资源*/
/*使用calloc而不是malloc,以便内存最初为空*/
char*s=calloc(2,1);
/*从标准输入一次读取一个字符*/
而((c=fgetc(stdin))!=EOF){
/*将字符放入字符串数组中的下一个位置*/
/*并将1添加到i中,使其索引数组中的下一个位置*/
s[i++]=c;
/*添加空终止符*/
s[i]=0;
/*我们拿到定界符了吗*/
如果(i>=delimlen&&!strcmp(s+i-delimlen,delim))
打破
/*如有必要,将内存s点的大小增加到*/
s=realloc(s,i+2);
}
printf(“我们得到了输入:%s”,s);
/*一旦完全使用完s,请释放内存以便再次使用*/
免费的;
出口(0);
}
请注意,如果您的输入来自终端(键盘),而不是来自文件或管道,则在将输入传递到程序之前,它将等待您点击“回车”。因此,在此之前,您不会看到分隔符。如果这是一个问题,请查看以下内容:
虽然
getdelim
是为这种情况定制的,但在这种情况下,不使用预置函数来获得学习体验是一个非常好的选择。如果我理解该任务,您希望从文件中读取所有数据(或stdin
),并且如果给定了一个替代分隔符(除正常的'\n'
)则使用该字符作为行尾,以便分隔和计数行
要处理输入,您只需读取/存储数组中的每个字符(不是分隔符)(在下面的示例中,我们将使用静态数组,但如果需要,您可以分配/realloc)。如果读取了新的可选分隔符,则终止该行,增加行数,并移动到下一个字符
一种基本方法是:
#include <stdio.h>
#define MAXC 512
int main (int argc, char **argv) {
int delim = argc > 1 ? *argv[1] : '\n';
char s[MAXC] = {0};
int c;
size_t nchr = 0, lines = 0;
/* for each char in input (stdin) */
while ((c = getchar()) != EOF) {
if (c == delim) { /* if delim, store newline */
s[nchr++] = '\n';
lines++;
}
else if (c != '\n') /* store char */
s[nchr++] = c;
/* check (MAX - 2) to allow protection - see below */
if (nchr == MAXC - 2) {
fprintf (stderr, "warning: MAXC reached.\n");
break;
}
}
/* protect against no terminating delim */
if (s[nchr-1] != delim) {
s[nchr++] = '\n';
lines++;
}
/* null-terminate */
s[nchr] = 0;
printf ("\nThere were '%zu' lines:\n\n", lines);
printf ("%s\n", s);
return 0;
}
示例输出
$ cat dat/captnjack_delim.txt
This is +a tale+
Of+ Captain Jack Sparrow+
A Pirate So Brave
On the +Seven Seas.
使用默认的'\n'
作为delim
注意:您还可以调整条件测试以处理'\n'
和'
替换以满足您的需要。如果您正在读取文件,则将使用fgetc
而不是getchar
等。。如果您还需要getdelim
示例,请告诉我
使用getdelim
使用带有动态内存分配的getdelim
也可以完成同样的事情。注意:最初分配了2
行的指针(#define MAXL 2
),这将强制重新分配行
,以处理超过2行的任何行。实际上,将其设置为合理预期的行数。(您希望尽可能减少分配/重新分配的数量。您也可以设置为1以强制每次分配新行,这样会降低效率)
开头包含的两个宏只需对calloc
分配执行错误检查,并删除任何尾随的回车
换行符
或分隔符
。(如果愿意,可以将这些移动到函数)
注意:由于getdelim
的工作方式,像这是一个故事+
这样的分隔符将导致初始和嵌入的换行符
包含在下一行中。您可以选择删除它们,但不要更改s
的起始地址,因为它是由getdelim
动态分配的。改为使用额外的指针和临时字符串
使用相同数据的简短示例如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXL 2
/* calloc with error check macro */
#define xcalloc(nmemb, size) \
({ void *memptr = calloc((size_t)nmemb, (size_t)size); \
if (!memptr) { \
fprintf(stderr, "error: virtual memory exhausted.\n"); \
exit(EXIT_FAILURE); \
} \
memptr; \
})
/* remove trailing '\r' '\n' and delim macro */
#define rmcrlfdelim(str, delim) \
({ char *p = (char *)str; \
int d = (int)delim; \
for (; *p; p++) {} \
p--; \
for (; p > str && (*p == '\n' || *p == '\r' || *p == d); p--) \
*p = 0, nchr--; \
})
int main (int argc, char **argv) {
int delim = argc > 1 ? *argv[1] : '\n';
char **lines = NULL;
char *s = NULL;
ssize_t nchr = 0;
size_t n = 0;
size_t nlines = 0;
size_t maxl = MAXL;
size_t i = 0;
lines = xcalloc (MAXL, sizeof *lines);
/* for each segment of input (stdin) */
while ((nchr = getdelim (&s, &n, delim, stdin)) != -1) {
rmcrlfdelim (s, delim); /* remove trailing \n \r delim */
lines[nlines++] = strdup (s); /* allocate/copy s to lines */
if (nlines == maxl) { /* realloc if needed */
void *tmp = realloc (lines, maxl * 2 * sizeof *lines);
if (!tmp) {
fprintf (stderr, "error: realloc - memory exhausted.\n");
exit (EXIT_FAILURE);
}
lines = (char **)tmp; /* below - set new pointers NULL */
memset (lines + maxl, 0, maxl * sizeof *lines);
maxl *= 2;
}
}
free (s); /* free mem allocated by getdelim */
printf ("\nThere were '%zu' lines:\n\n", nlines);
for (i = 0; i < nlines; i++)
printf ("%s\n", lines[i]);
for (i = 0; i < nlines; i++) /* free allocated memory */
free (lines[i]);
free (lines);
return 0;
}
使用'+'
作为delim
首先:不使用制表符就可以正确缩进代码,因为普通人看不懂。你真是个好人,@chux@alk,开个玩笑d将编译器的警告级别设置为最大值。认真对待警告。您可能想学习如何使用调试器,以及如何使用Valgrind()之类的内存检查器。只是想一想——您的分隔符不应该是
int
而不是字符串吗?不。。分隔符(根据原始问题)是一行中三个“0”字符的序列。。这就是代码要查找的内容。如果它是一个整数delim=0,那么您如何知道只查找一个数字0、两个数字还是三个?“\000”是空字符的八进制文字,是的。但这不是我要找的分隔符。我正在寻找三个字符“000”的ASCII序列。我不知道为什么终止序列是“000”
,但这就是问题的提问者所要求的。这是100%确定的,这就是为什么我用一个想法限定我的评论。。
$ ./bin/getchar_delim + <dat/captnjack_delim.txt
There were '6' lines:
This is
a tale
Of
Captain Jack Sparrow
A Pirate So BraveOn the
Seven Seas.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXL 2
/* calloc with error check macro */
#define xcalloc(nmemb, size) \
({ void *memptr = calloc((size_t)nmemb, (size_t)size); \
if (!memptr) { \
fprintf(stderr, "error: virtual memory exhausted.\n"); \
exit(EXIT_FAILURE); \
} \
memptr; \
})
/* remove trailing '\r' '\n' and delim macro */
#define rmcrlfdelim(str, delim) \
({ char *p = (char *)str; \
int d = (int)delim; \
for (; *p; p++) {} \
p--; \
for (; p > str && (*p == '\n' || *p == '\r' || *p == d); p--) \
*p = 0, nchr--; \
})
int main (int argc, char **argv) {
int delim = argc > 1 ? *argv[1] : '\n';
char **lines = NULL;
char *s = NULL;
ssize_t nchr = 0;
size_t n = 0;
size_t nlines = 0;
size_t maxl = MAXL;
size_t i = 0;
lines = xcalloc (MAXL, sizeof *lines);
/* for each segment of input (stdin) */
while ((nchr = getdelim (&s, &n, delim, stdin)) != -1) {
rmcrlfdelim (s, delim); /* remove trailing \n \r delim */
lines[nlines++] = strdup (s); /* allocate/copy s to lines */
if (nlines == maxl) { /* realloc if needed */
void *tmp = realloc (lines, maxl * 2 * sizeof *lines);
if (!tmp) {
fprintf (stderr, "error: realloc - memory exhausted.\n");
exit (EXIT_FAILURE);
}
lines = (char **)tmp; /* below - set new pointers NULL */
memset (lines + maxl, 0, maxl * sizeof *lines);
maxl *= 2;
}
}
free (s); /* free mem allocated by getdelim */
printf ("\nThere were '%zu' lines:\n\n", nlines);
for (i = 0; i < nlines; i++)
printf ("%s\n", lines[i]);
for (i = 0; i < nlines; i++) /* free allocated memory */
free (lines[i]);
free (lines);
return 0;
}
$ ./bin/getdelim <dat/captnjack_delim.txt
There were '4' lines:
This is +a tale+
Of+ Captain Jack Sparrow+
A Pirate So Brave
On the +Seven Seas.
$ ./bin/getdelim + <dat/captnjack_delim.txt
There were '6' lines:
This is
a tale
Of
Captain Jack Sparrow
A Pirate So Brave
On the
Seven Seas.
lines[ 0] : This is
lines[ 1] : a tale
lines[ 2] :
Of
lines[ 3] : Captain Jack Sparrow
lines[ 4] :
A Pirate So Brave
On the
lines[ 5] : Seven Seas.