如果我的程序将通过stdin
传入大量的数字列表,那么最有效的方法是什么呢?
我将要传入该计划的输入将采用以下格式:
3,5;6,7;8,9;11,4;;
我需要处理输入,以便我可以使用冒号之间的数字(即我希望能够使用3和5,6和7等等)。 ;;
表示它是该行的结尾。
我正在考虑使用缓冲读取器来读取整行,然后使用parseInt。
这是最有效的方法吗?
答案 0 :(得分:3)
这是一个有效的解决方案 一种方法是使用strtok()并将值存储在数组中。理想情况下,动态分配。
int main(int argc, char *argv[])
{
int lst_size=100;
int line_size=255;
int lst[lst_size];
int count=0;
char buff[line_size];
char * token=NULL;
fgets (buff, line_size, stdin); //Get input
通过'使用strtok,'和';'作为代理人。
token=strtok(buff, ";,");
lst[count++]=atoi(token);
while(token=strtok(NULL, ";,")){
lst[count++]=atoi(token);
}
最后你需要考虑双重&#34 ;;;"通过将计数减少1,因为atoi(令牌)将为该情况返回0并将其存储在第n个索引中。你不想要的。
count--;
}
答案 1 :(得分:2)
我在C上有点生疏,但这对你有用吗?
char[1000] remainder;
int first, second;
fp = fopen("C:\\file.txt", "r"); // Error check this, probably.
while (fgets(&remainder, 1000, fp) != null) { // Get a line.
while (sscanf(remainder, "%d,%d;%s", first, second, remainder) != null) {
// place first and second into a struct or something
}
}
答案 2 :(得分:2)
您可以使用 fgets 或 fgetc 从 stdin 中读取内容。您也可以使用 getline() ,因为您正在从stdin读取。
读完该行后,您可以将 strtok() 与分隔符一起使用";"将字符串拆分为分号。你可以循环直到strok()为null,或者在这种情况下,&#39 ;;'。同样在C中,您应该使用 atoi() 将字符串转换为整数。
例如:
int length = 256;
char* str = (char*)malloc(length);
int err = getline(&str, &length, stdin);
答案 3 :(得分:2)
我会在命令args中读取,然后使用strtok()
库方法
http://man7.org/linux/man-pages/man3/strtok.3.html
(以上网址引用的网页甚至包含如何使用它的代码示例。)
答案 4 :(得分:2)
另一种相当优雅的方法是允许strtol
通过将要读取的字符串推进到endptr
返回strtol
来解析输入。结合根据需要分配/重新分配的数组,您应该能够处理任何长度的行(直到内存耗尽)。下面的示例使用单个数组作为数据。如果要存储多行,每个行作为一个单独的数组,可以使用相同的方法,但从指向int的指针数组的指针开始。 (即int **numbers
并分配指针,然后分配每个数组)。如果您有疑问,请告诉我们:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define NMAX 256
int main () {
char *ln = NULL; /* NULL forces getline to allocate */
size_t n = 0; /* max chars to read (0 - no limit) */
ssize_t nchr = 0; /* number of chars actually read */
int *numbers = NULL; /* array to hold numbers */
size_t nmax = NMAX; /* check for reallocation */
size_t idx = 0; /* numbers array index */
if (!(numbers = calloc (NMAX, sizeof *numbers))) {
fprintf (stderr, "error: memory allocation failed.");
return 1;
}
/* read each line from stdin - dynamicallly allocated */
while ((nchr = getline (&ln, &n, stdin)) != -1)
{
char *p = ln; /* pointer for use with strtol */
char *ep = NULL;
errno = 0;
while (errno == 0)
{
/* parse/convert each number on stdin */
numbers[idx] = strtol (p, &ep, 10);
/* note: overflow/underflow checks omitted */
/* if valid conversion to number */
if (errno == 0 && p != ep)
{
idx++; /* increment index */
if (!ep) break; /* check for end of str */
}
/* skip delimiters/move pointer to next digit */
while (*ep && (*ep <= '0' || *ep >= '9')) ep++;
if (*ep)
p = ep;
else
break;
/* reallocate numbers if idx = nmax */
if (idx == nmax)
{
int *tmp = realloc (numbers, 2 * nmax * sizeof *numbers);
if (!tmp) {
fprintf (stderr, "Error: struct reallocation failure.\n");
exit (EXIT_FAILURE);
}
numbers = tmp;
memset (numbers + nmax, 0, nmax * sizeof *numbers);
nmax *= 2;
}
}
}
/* free mem allocated by getline */
if (ln) free (ln);
/* show values stored in array */
size_t i = 0;
for (i = 0; i < idx; i++)
printf (" numbers[%2zu] %d\n", i, numbers[i]);
/* free mem allocate to numbers */
if (numbers) free (numbers);
return 0;
}
<强>输出强>
$ echo "3,5;6,7;8,9;11,4;;" | ./bin/prsistdin
numbers[ 0] 3
numbers[ 1] 5
numbers[ 2] 6
numbers[ 3] 7
numbers[ 4] 8
numbers[ 5] 11
numbers[ 6] 4
也适用于将字符串存储在文件中的位置:
$ cat dat/numsemic.csv | ./bin/prsistdin
or
$ ./bin/prsistdin < dat/numsemic.csv
fgets
而不使用size_t
需要做一些修改才能提出一个我很满意的修订版本{@ 1}}并替换getline
。 fgets
更加灵活,为您处理空间分配,getline
由您决定。 (更不用说fgets
返回实际读取的字符数而无需调用getline
)。
我的目标是保持阅读任何长度线以满足您的要求的能力。这或者意味着最初分配一些巨大的行缓冲区(浪费)或提出一个方案,如果它比最初分配给strlen
的空间长,它将根据需要重新分配输入行缓冲区。 (这是ln
做得很好的事情)。我对结果非常满意。 注意:我将重新分配代码放在函数中以保持getline
合理清洁。 脚注2
看看以下代码。注意,我已经在代码中保留了main
预处理程序指令,允许您使用DEBUG
标志进行编译,如果您希望每次分配时都将其吐出。 [脚注1] 您可以使用以下代码编译代码:
-DDEBUG
或者如果您想要调试输出(例如将LMAX设置为gcc -Wall -Wextra -o yourexename yourfilename.c
或小于行长度),请使用以下命令:
2
如果您有任何疑问,请与我们联系:
gcc -Wall -Wextra -o yourexename yourfilename.c -DDEBUG
脚注1
单词#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define NMAX 256
#define LMAX 1024
char *realloc_char (char *sp, unsigned int *n); /* reallocate char array */
int *realloc_int (int *sp, unsigned int *n); /* reallocate int array */
char *fixshortread (FILE *fp, char **s, unsigned int *n); /* read all stdin */
int main () {
char *ln = NULL; /* dynamically allocated for fgets */
int *numbers = NULL; /* array to hold numbers */
unsigned int nmax = NMAX; /* numbers check for reallocation */
unsigned int lmax = LMAX; /* ln check for reallocation */
unsigned int idx = 0; /* numbers array index */
unsigned int i = 0; /* simple counter variable */
char *nl = NULL;
/* initial allocation for numbers */
if (!(numbers = calloc (NMAX, sizeof *numbers))) {
fprintf (stderr, "error: memory allocation failed (numbers).");
return 1;
}
/* initial allocation for ln */
if (!(ln = calloc (LMAX, sizeof *ln))) {
fprintf (stderr, "error: memory allocation failed (ln).");
return 1;
}
/* read each line from stdin - dynamicallly allocated */
while (fgets (ln, lmax, stdin) != NULL)
{
/* provide a fallback to read remainder of line
if the line length exceeds lmax */
if (!(nl = strchr (ln, '\n')))
fixshortread (stdin, &ln, &lmax);
else
*nl = 0;
char *p = ln; /* pointer for use with strtol */
char *ep = NULL;
errno = 0;
while (errno == 0)
{
/* parse/convert each number on stdin */
numbers[idx] = strtol (p, &ep, 10);
/* note: overflow/underflow checks omitted */
/* if valid conversion to number */
if (errno == 0 && p != ep)
{
idx++; /* increment index */
if (!ep) break; /* check for end of str */
}
/* skip delimiters/move pointer to next digit */
while (*ep && (*ep <= '0' || *ep >= '9')) ep++;
if (*ep)
p = ep;
else
break;
/* reallocate numbers if idx = nmax */
if (idx == nmax)
realloc_int (numbers, &nmax);
}
}
/* free mem allocated by getline */
if (ln) free (ln);
/* show values stored in array */
for (i = 0; i < idx; i++)
printf (" numbers[%2u] %d\n", (unsigned int)i, numbers[i]);
/* free mem allocate to numbers */
if (numbers) free (numbers);
return 0;
}
/* reallocate character pointer memory */
char *realloc_char (char *sp, unsigned int *n)
{
char *tmp = realloc (sp, 2 * *n * sizeof *sp);
#ifdef DEBUG
printf ("\n reallocating %u to %u\n", *n, *n * 2);
#endif
if (!tmp) {
fprintf (stderr, "Error: char pointer reallocation failure.\n");
exit (EXIT_FAILURE);
}
sp = tmp;
memset (sp + *n, 0, *n * sizeof *sp); /* memset new ptrs 0 */
*n *= 2;
return sp;
}
/* reallocate integer pointer memory */
int *realloc_int (int *sp, unsigned int *n)
{
int *tmp = realloc (sp, 2 * *n * sizeof *sp);
#ifdef DEBUG
printf ("\n reallocating %u to %u\n", *n, *n * 2);
#endif
if (!tmp) {
fprintf (stderr, "Error: int pointer reallocation failure.\n");
exit (EXIT_FAILURE);
}
sp = tmp;
memset (sp + *n, 0, *n * sizeof *sp); /* memset new ptrs 0 */
*n *= 2;
return sp;
}
/* if fgets fails to read entire line, fix short read */
char *fixshortread (FILE *fp, char **s, unsigned int *n)
{
unsigned int i = 0;
int c = 0;
i = *n - 1;
realloc_char (*s, n);
do
{
c = fgetc (fp);
(*s)[i] = c;
i++;
if (i == *n)
realloc_char (*s, n);
} while (c != '\n' && c != EOF);
(*s)[i-1] = 0;
return *s;
}
的选择没有什么特别之处(可能是DEBUG
等等),要带走的一点是,如果你想有条件地包含/排除代码,你可以只需使用预处理器标志即可。您只需添加DOG
即可将-Dflagname
传递给编译器。
脚注2
您可以将重新分配函数组合到单个flagname
函数中,该函数接受void指针作为其参数以及要重新分配的类型的void*
,并返回指向重新分配空间的void指针 - - 但我们将把它留给以后。
答案 5 :(得分:1)
getchar_unlocked()
正是您要找的。 p>
以下是代码:
#include <stdio.h>
inline int fastRead_int(int * x)
{
register int c = getchar_unlocked();
*x = 0;
// clean stuff in front of + look for EOF
for(; ((c<48 || c>57) && c != EOF); c = getchar_unlocked());
if(c == EOF)
return 0;
// build int
for(; c>47 && c<58 ; c = getchar_unlocked()) {
*x = (*x<<1) + (*x<<3) + c - 48;
}
return 1;
}
int main()
{
int x;
while(fastRead_int(&x))
printf("%d ",x);
return 0;
}
对于输入1;2;2;;3;;4;;;;;54;;;;
,上面的代码会生成1 2 2 3 4 54
。
我保证,此解决方案比本主题中介绍的其他解决方案快得多。它不仅使用getchar_unlocked()
,还使用register
,inline
以及乘以10个棘手的方式:(*x<<1) + (*x<<3)
。
祝你找到更好的解决方案,祝你好运。