답변:
동적 메모리 관리가 필요하고 fgets
기능을 사용 하여 라인을 읽습니다. 그러나 얼마나 많은 문자를 읽었는지 확인할 방법이없는 것 같습니다. 따라서 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;
}
참고 : get을 사용하지 마십시오! 경계 검사를 수행하지 않으며 버퍼를 오버플로 할 수 있습니다.
fgetc_unlocked
스레드 안전성이 문제가 아니지만 성능이 중요하다면 덜 이식성이있는 것을 사용할 수 있습니다 .
getline()
POSIX 표준 getline()
기능 과 다릅니다 .
정적 할당을 위해 줄을 읽는 매우 간단하지만 안전하지 않은 구현 :
char line[1024];
scanf("%[^\n]", line);
버퍼 오버플로의 가능성은 없지만 전체 행을 읽지 않을 가능성이있는 더 안전한 구현은 다음과 같습니다.
char line[1024];
scanf("%1023[^\n]", line);
변수를 선언하는 지정된 길이와 형식 문자열에 지정된 길이 사이의 '1만큼 차이'가 아닙니다. 역사적인 유물입니다.
gets
모두 표준에서 제거
따라서 명령 인수를 찾고 있다면 Tim의 대답을 살펴보십시오. 콘솔에서 한 줄을 읽고 싶다면 :
#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로 콘솔에서 한 줄을 읽는가?"와 같은 질문을 볼 때, 나는 사람이 100 줄의 코드가 아닌 gets ()와 같은 간단한 것을 필요로한다고 가정한다. 위와 같이. 실제로 100 줄의 코드를 실제로 작성하려고하면 실수를 더 많이하게 될 것이라고 생각합니다.
gets
더 이상 존재하지 않으므로 C11에서는 작동하지 않습니다.
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 상위 집합 인 getline
으로 확인됩니다.
증가가 필요할 때마다 할당 된 메모리를 두 배로 늘리고 스레드로부터 안전 해 보입니다.
매크로 확장이 필요하지만 훨씬 더 잘할 수는 없습니다.
len
여기에 있는 목적은 무엇입니까 , 읽을 때 길이도 제공됩니다
man getline
. len
는 기존 버퍼의 길이이며, 0
마법이며 할당하도록 지시합니다. 읽기는 읽은 문자 수입니다. 버퍼 크기는보다 클 수 있습니다 read
.
저와 같은 많은 사람들이 검색된 제목과 일치하는 제목으로이 게시물을 찾습니다. 설명은 가변 길이에 대해 말하고 있습니다. 대부분의 경우 길이를 미리 알고 있습니다.
미리 길이를 알고 있다면 아래에서 시도해보십시오.
char str1[1001] = { 0 };
fgets(str1, 1001, stdin); // 1000 chars may be read
출처 : https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
제안 된대로 getchar ()를 사용하여 줄 끝이나 EOF가 반환 될 때까지 콘솔에서 읽을 수 있으며 자체 버퍼를 구축 할 수 있습니다. 적절한 최대 라인 크기를 설정할 수없는 경우 버퍼가 동적으로 증가 할 수 있습니다.
또한 fgets를 사용하여 C null로 끝나는 문자열로 라인을 얻는 안전한 방법을 사용할 수 있습니다.
#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);
콘솔 입력을 모두 사용했거나 어떤 이유로 작업이 실패한 경우 eof == NULL이 반환되고 라인 버퍼가 변경되지 않을 수 있습니다 (이것이 첫 번째 문자를 '\ 0'으로 설정하는 것이 편리한 이유입니다).
fgets는 line []을 넘치지 않으며 성공적인 리턴시 마지막으로 승인 된 문자 뒤에 널이 있는지 확인합니다.
줄 끝에 도달하면 '\ 0'으로 끝나는 앞의 문자는 '\ n'이됩니다.
종료 '\ 0'전에 종료 '\ n'이 없으면 더 많은 데이터가 있거나 다음 요청이 파일 끝을보고 할 수 있습니다. 어느 것이 무엇인지 결정하기 위해 다른 fgets를 수행해야합니다. (이 점에서 getchar ()로 반복하는 것이 더 쉽습니다.)
위의 (업데이트 된) 예제 코드에서, 성공적인 fgets 후 line [sizeof (line) -1] == '\ 0'이면 버퍼가 완전히 채워진 것을 알 수 있습니다. 그 위치가 '\ n'에 의해 진행된다면 당신은 운이 좋았다는 것을 알고 있습니다. 그렇지 않으면 stdin에 더 많은 데이터 또는 파일 끝이 있습니다. (버퍼가 완전히 채워지지 않은 경우에도 여전히 파일의 끝에있을 수 있으며 현재 줄 끝에 '\ n'이 없을 수도 있습니다. 문자열을 검색하여 찾아야하기 때문에 / 또는 문자열 끝 (버퍼의 첫 번째 '\ 0') 앞의 '\ n'을 제거하면 처음부터 getchar ()를 사용하는 것을 선호합니다.)
첫 번째 청크로 읽은 양보다 더 많은 줄이있는 것을 처리하기 위해해야 할 일을하십시오. 동적으로 늘어나는 버퍼의 예는 getchar 또는 fget과 함께 작동하도록 만들 수 있습니다. 주의해야 할 몇 가지 까다로운 경우가 있습니다 (예 : 버퍼가 확장되기 전에 이전 입력을 종료 한 '\ 0'위치에 다음 입력이 저장되기 시작하는 것을 기억하는 것과 같은).
콘솔에서 C로 줄을 읽는 방법은 무엇입니까?
자신의 기능을 구축하는 것은 콘솔에서 한 줄을 읽는 데 도움이되는 방법 중 하나입니다.
할당 된 메모리를 모두 사용하려고 할 때 메모리 크기를 두 배로 늘리려 고합니다.
그리고 여기 getchar()
에서는 사용자가 입력 '\n'
하거나 EOF
문자를 입력 할 때까지 함수를 사용하여 문자열의 각 문자를 하나씩 스캔하는 루프를 사용하고 있습니다.
마지막으로 라인을 반환하기 전에 추가로 할당 된 메모리를 제거합니다.
//the function to read lines of variable length
char* scan_line(char *line)
{
int ch; // as getchar() returns `int`
long capacity = 0; // capacity of the buffer
long length = 0; // maintains the length of the string
char *temp = NULL; // use additional pointer to perform allocations in order to avoid memory leaks
while ( ((ch = getchar()) != '\n') && (ch != EOF) )
{
if((length + 1) >= capacity)
{
// resetting capacity
if (capacity == 0)
capacity = 2; // some initial fixed length
else
capacity *= 2; // double the size
// try reallocating the memory
if( (temp = realloc(line, capacity * sizeof(char))) == NULL ) //allocating memory
{
printf("ERROR: unsuccessful allocation");
// return line; or you can exit
exit(1);
}
line = temp;
}
line[length] = (char) ch; //type casting `int` to `char`
}
line[length + 1] = '\0'; //inserting null character at the end
// remove additionally allocated memory
if( (temp = realloc(line, (length + 1) * sizeof(char))) == NULL )
{
printf("ERROR: unsuccessful allocation");
// return line; or you can exit
exit(1);
}
line = temp;
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
}
샘플 입력 :
Twinkle Twinkle little star.... in the sky!
샘플 출력 :
Twinkle Twinkle little star.... in the sky!
나는 얼마 전에 같은 문제를 만났고 이것이 나의 해결책이었습니다.
/*
* 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;
}
goto
오류 사례를 처리하는 데 사용하면 코드가 훨씬 간단 해집니다 . 그럼에도 불구하고 루프에서 동일한 크기로 반복하는 tmp_buf
대신 재사용 할 수 있다고 생각하지 malloc
않습니까?
has_err
를 사용하여 오류를보고하면이 함수가 스레드에 안전하지 않고 사용하기가 불편 해집니다. 그렇게하지 마십시오. NULL을 반환하여 이미 오류를 나타냅니다. 또한 인쇄 된 오류 메시지가 범용 라이브러리 함수에서 좋은 생각이 아니라고 생각할 여지가 있습니다.
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
널 (null) 종료하지 않고 포함 \n
(또는 플랫폼을 사용하고 무엇이든)은 결국. 스트림에서 다음 I / O 작업 후에는 무효화됩니다.
이 같은:
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;
}
콘솔에서 한 줄을 읽는 가장 쉽고 간단한 방법은 getchar () 함수를 사용하여 한 번에 한 문자를 배열에 저장하는 것입니다.
{
char message[N]; /* character array for the message, you can always change the character length */
int i = 0; /* loop counter */
printf( "Enter a message: " );
message[i] = getchar(); /* get the first character */
while( message[i] != '\n' ){
message[++i] = getchar(); /* gets the next character */
}
printf( "Entered message is:" );
for( i = 0; i < N; i++ )
printf( "%c", message[i] );
return ( 0 );
}
이 함수는 원하는 작업을 수행해야합니다.
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 );
이게 도움이 되길 바란다.
fgets( buffer, sizeof(buffer), file );
말아야 sizeof(buffer)-1
합니다. fgets
종료 널을위한 공간을 남깁니다.
while (!feof(file))
항상 잘못 이 잘못된 사용의 또 하나의 예입니다.