如何从C中的控制台读取一行?
在C控制台程序中读取完整行的最简单方法是什么?input的文本可能具有可变长度,我们不能对其内容做任何假设。
您需要dynamic内存pipe理,并使用fgets
函数来读取您的行。 但是,似乎没有办法看到它读取了多less个字符。 所以你使用fgetc:
char * getline(void) { char * line = malloc(100), * linep = line; size_t lenmax = 100, len = lenmax; int c; if(line == NULL) return NULL; for(;;) { c = fgetc(stdin); if(c == EOF) break; if(--len == 0) { len = lenmax; char * linen = realloc(linep, lenmax *= 2); if(linen == NULL) { free(linep); return NULL; } line = linen + (line - linep); linep = linen; } if((*line++ = c) == '\n') break; } *line = '\0'; return linep; }
注意 :永远不要使用获取! 它不会执行边界检查,并可能溢出您的缓冲区
如果您使用的是GNU C库或其他符合POSIX的库,则可以使用getline()
并将stdin
传递给文件stream。
您可能需要按字符(getc())循环使用字符,以确保您没有缓冲区溢出,并且不会截断input。
所以,如果你正在寻找命令的参数,看看蒂姆的答案。 如果您只想从控制台读取一行:
#include <stdio.h> int main() { char string [256]; printf ("Insert your full address: "); gets (string); printf ("Your address is: %s\n",string); return 0; }
是的,这是不安全的,你可以做缓冲区溢出,它不检查文件的结尾,它不支持编码和其他许多东西。 其实我甚至都没有想过是否这样做。 我同意我有点搞砸了:)但是…当我看到一个像“如何从C语言中的控制台读取一行”的问题时,我假设一个人需要一些简单的东西,比如gets()而不是100行代码像上面一样。 其实,我想,如果你试图在现实中写出这100行代码,你会犯更多的错误,比你select得到的要多;)
读取静态分配行的一个非常简单但不安全的实现:
char line[1024]; scanf("%[^\n]", line);
一个更安全的实现,没有缓冲区溢出的可能性,但有可能不读取整个行,是:
char line[1024]; scanf("%1023[^\n]", line);
不是声明variables的长度与格式string中指定的长度之间的“差别”。 这是一个历史的艺术品。
getline
可运行示例
在这个答案中提到,但这里是一个例子。
它是POSIX 7 ,为我们分配内存,并很好地重用循环中分配的缓冲区。
指针newbs,阅读此: 为什么getline的第一个参数指针指针“char **”而不是“char *”?
#define _XOPEN_SOURCE 700 #include <stdio.h> #include <stdlib.h> int main(void) { char *line = NULL; size_t len = 0; ssize_t read = 0; while (read != -1) { puts("enter a line"); read = getline(&line, &len, stdin); printf("line = %s", line); printf("line length = %zu\n", read); puts(""); } free(line); return 0; }
glibc的实现
没有POSIX? 也许你想看看glibc 2.23的实现 。
它解决了getdelim
,这是一个简单的POSIX getdelim
的任意行终止符的getline
。
每当需要增加时,它将分配的内存加倍,并且看起来是线程安全的。
这需要一些macros观的扩展,但是你不太可能做得更好。
正如所build议的那样,您可以使用getchar()从控制台读取,直到返回行尾或EOF,构build您自己的缓冲区。 如果您无法设置合理的最大线路大小,则会dynamic增加缓冲区。
你也可以使用fgets作为一个安全的方式来获得一个C为null的string:
#include <stdio.h> char line[1024]; /* Generously large value for most situations */ char *eof; line[0] = '\0'; /* Ensure empty line if no input delivered */ line[sizeof(line)-1] = ~'\0'; /* Ensure no false-null at end of buffer */ eof = fgets(line, sizeof(line), stdin);
如果控制台input已经耗尽,或者由于某种原因操作失败,则返回eof == NULL,并且行缓冲区可能保持不变(这就是为什么将第一个字符设置为“\ 0”的原因)。
fgets将不会溢出行[],并且会确保在成功返回后最后接受的字符后有一个空值。
如果达到行尾,终止'\ 0'之前的字符将是'\ n'。
如果在结束“\ 0”之前没有终止'\ n',可能是有更多的数据或下一个请求将报告文件结束。 你将不得不做另一个fgets来确定哪个是哪个。 (在这方面,使用getchar()循环更容易。)
在上面的(更新的)示例代码中,如果在成功执行fgets之后,行[sizeof(line)-1] =='\ 0',则知道缓冲区已被完全填充。 如果那个位置是由一个'\ n'进行的,你就知道你是幸运的。 否则,在标准input前面会有更多的数据或文件结束。 (当缓冲区没有被完全填充时,你仍然可以在文件结尾,也可能在当前行的末尾没有'\ n',因为你必须扫描string来查找和/或者在string结尾(缓冲区中的第一个'\ 0')之前消除任何'\ n',我倾向于首先使用getchar()。
做你需要做的事来处理还有更多的线条比你读的第一块。 dynamic增长缓冲区的例子可以使用getchar或fgets来工作。 有一些棘手的边缘情况需要注意(比如记住下一个input开始存储在'\ 0'的位置,在缓冲区被扩展之前结束之前的input)。
很多人和我一样,来到这个post,标题与search的内容相匹配,尽pipe描述是关于变长的。 对于大多数情况,我们事先知道这个长度。
如果您事先知道长度,请尝试以下方法:
char str1[1001] = { 0 }; fgets(str1, 1001, stdin); // 1000 chars may be read
来源: https : //www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
前段时间我遇到同样的问题,这是我的solutuion,希望它有帮助。
/* * Initial size of the read buffer */ #define DEFAULT_BUFFER 1024 /* * Standard boolean type definition */ typedef enum{ false = 0, true = 1 }bool; /* * Flags errors in pointer returning functions */ bool has_err = false; /* * Reads the next line of text from file and returns it. * The line must be free()d afterwards. * * This function will segfault on binary data. */ char *readLine(FILE *file){ char *buffer = NULL; char *tmp_buf = NULL; bool line_read = false; int iteration = 0; int offset = 0; if(file == NULL){ fprintf(stderr, "readLine: NULL file pointer passed!\n"); has_err = true; return NULL; } while(!line_read){ if((tmp_buf = malloc(DEFAULT_BUFFER)) == NULL){ fprintf(stderr, "readLine: Unable to allocate temporary buffer!\n"); if(buffer != NULL) free(buffer); has_err = true; return NULL; } if(fgets(tmp_buf, DEFAULT_BUFFER, file) == NULL){ free(tmp_buf); break; } if(tmp_buf[strlen(tmp_buf) - 1] == '\n') /* we have an end of line */ line_read = true; offset = DEFAULT_BUFFER * (iteration + 1); if((buffer = realloc(buffer, offset)) == NULL){ fprintf(stderr, "readLine: Unable to reallocate buffer!\n"); free(tmp_buf); has_err = true; return NULL; } offset = DEFAULT_BUFFER * iteration - iteration; if(memcpy(buffer + offset, tmp_buf, DEFAULT_BUFFER) == NULL){ fprintf(stderr, "readLine: Cannot copy to buffer\n"); free(tmp_buf); if(buffer != NULL) free(buffer); has_err = true; return NULL; } free(tmp_buf); iteration++; } return buffer; }
我会改变@ litb的答案
char *getline(void) { char* accumulator = malloc(100); char readBuf[100]; int accumulatorSize = 100; *accumulator = '\0'; while (!feof(stdin)) { fgets(readBuf, 99, stdin); strcat(accumulator, readBuf); /* possible fencepost error here */ if (readBuf[strlen(readBuf)] != '\n') { accumulatorSize += 100; accumulator = realloc(accumulator, accumulatorSize); /* should probably check for realloc returning null */ } else break; } return accumulator; }
请记住,这是比我11年来写的更加纯粹的C代码。
在BSD系统和Android上,你也可以使用fgetln
:
#include <stdio.h> char * fgetln(FILE *stream, size_t *len);
像这样:
size_t line_len; const char *line = fgetln(stdin, &line_len);
该line
不是空终止,并包含\n
(或任何您的平台正在使用)。 stream在下一个I / O操作后,它变为无效。
如何从C中的控制台读取一行?
-
build立你自己的function ,是帮助你实现从C语言控制台读取一行的方法之一。
-
我正在使用dynamic内存分配来分配只需要足够的内存容量来保存行的所有字符以及
'\0'
字符。 -
在这里,我使用循环扫描string的每个字符使用
getchar()
函数,直到用户input'\n'
或EOF
字符//the function to read lines of variable length char* scan_line(char *line) { int ch; //as getchar() returns `int` if( (line = malloc(sizeof(char))) == NULL) //allocating memory { //checking if allocation was successful or not printf("unsuccessful allocation"); exit(1); } line[0]='\0'; for(int index = 0; ( (ch = getchar())!='\n' ) && (ch != EOF) ; index++) { if( (line = realloc(line, (index + 2)*sizeof(char))) == NULL ) { //checking if reallocation was successful or not printf("unsuccessful reallocation"); exit(1); } line[index] = (char) ch; //type casting `int` to `char` line[index + 1] = '\0'; //inserting null character at the end } return line; }
-
现在你可以用这种方式阅读完整的一行:
char *line = NULL; line = scan_line(line);
这是一个使用scan_line()
函数的示例程序 :
#include <stdio.h> #include <stdlib.h> //for dynamic allocation functions char* scan_line(char *line) { .......... } int main(void) { char *a = NULL; a = scan_line(a); //function call to scan the line printf("%s\n",a); //printing the scanned line free(a); //don't forget to free the malloc'd pointer }
样本input:
Twinkle Twinkle little star.... in the sky!
样本输出:
Twinkle Twinkle little star.... in the sky!
像这样的东西:
unsigned int getConsoleInput(char **pStrBfr) //pass in pointer to char pointer, returns size of buffer { char * strbfr; int c; unsigned int i; i = 0; strbfr = (char*)malloc(sizeof(char)); if(strbfr==NULL) goto error; while( (c = getchar()) != '\n' && c != EOF ) { strbfr[i] = (char)c; i++; strbfr = (void*)realloc((void*)strbfr,sizeof(char)*(i+1)); //on realloc error, NULL is returned but original buffer is unchanged //NOTE: the buffer WILL NOT be NULL terminated since last //chracter came from console if(strbfr==NULL) goto error; } strbfr[i] = '\0'; *pStrBfr = strbfr; //successfully returns pointer to NULL terminated buffer return i + 1; error: *pStrBfr = strbfr; return i + 1; }
这个函数应该做你想要的:
char* readLine( FILE* file ) { char buffer[1024]; char* result = 0; int length = 0; while( !feof(file) ) { fgets( buffer, sizeof(buffer), file ); int len = strlen(buffer); buffer[len] = 0; length += len; char* tmp = (char*)malloc(length+1); tmp[0] = 0; if( result ) { strcpy( tmp, result ); free( result ); result = tmp; } strcat( result, buffer ); if( strstr( buffer, "\n" ) break; } return result; } char* line = readLine( stdin ); /* Use it */ free( line );
我希望这有帮助。