답변:
동적 메모리 관리가 필요하고 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))항상 잘못 이 잘못된 사용의 또 하나의 예입니다.