programing

getline의 첫 번째 인수가 "char*" 대신 포인터 "char**"를 가리키는 포인터인 이유는 무엇입니까?

closeapi 2023. 10. 3. 09:20
반응형

getline의 첫 번째 인수가 "char*" 대신 포인터 "char**"를 가리키는 포인터인 이유는 무엇입니까?

사용합니다.getline한 줄을 읽어내는 기능STDIN.

의 원형.getline다음과 같습니다.

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

는 이것을 http://www.crasseux.com/books/ctutorial/getline.html#getline 에서 얻는 테스트 프로그램으로 사용합니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int atgc, char *argv[])
{
    int bytes_read = 1;
    int nbytes = 10;
    char *my_string;

    my_string = (char *)malloc(nbytes+1);

    puts("Please enter a line of text");

    bytes_read = getline(&my_string, &nbytes, stdin);

    if (bytes_read == -1)
    {
        puts ("ERROR!");
    }
    else
    {
        puts ("You typed:");
        puts (my_string);
    }

    return 0;
}

이 정도면 잘 됩니다.

내가 의심하는 건?

  1. 사용 이유char **lineptr대신char *lineptr기능의 척도로서.getline?

  2. 다음 코드를 사용할 때 잘못된 이유:

    char **my_string;
    bytes_read = getline(my_string, &nbytes, stdin); 
    
  3. 나는 와 혼동하고 있습니다.*그리고.&.

다음은 경고의 일부입니다.

testGetline.c: In function ‘main’: 
testGetline.c:34: warning: pointer targets in passing argument 2 of  
  ‘getline’ differ in signedness 
/usr/include/stdio.h:671: 
  note: expected ‘size_t * __restrict__’ but argument is of type ‘int *’  
testGetline.c:40: warning: passing argument 1 of ‘putchar’ makes integer 
  from pointer without a cast 
/usr/include/stdio.h:582: note: expected ‘int’ but argument is of 
  type ‘char *’

저는 GCC 버전 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)를 사용합니다.

사용 이유char **lineptr대신에char *lineptr기능의 척도로서.getline?

시제품을 상상해 보십시오.getline다음과 같이 보입니다.

ssize_t
getline(char *line, size_t n, FILE *stream);

그리고 당신은 이렇게 불렀죠

char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(buffer, len, stdin);

전화하기전getline,buffernull:

+------+
|buffer+-------> NULL
+------+

언제getline라고 합니다.line등본을 보다buffer함수 인수는 C에서 값으로 전달되기 때문입니다.안에서.getline, 우리는 더 이상 접근할 수 없습니다.buffer:

+------+
|buffer+-------> NULL
+------+          ^
                  |
+------+          |
| line +----------+
+------+

getline메모리를 할당합니다.malloc포인트들을line블록의 시작 부분까지:

+------+
|buffer+-------> NULL
+------+

+------+        +---+---+---+---+---+
| line +------->+   |   |   |   |   |
+------+        +---+---+---+---+---+

끝나고getline반품, 우리는 더 이상 접근할 수 없습니다.line:

+------+
|buffer+-------> NULL
+------+

그리고 우리는 우리가 시작했던 곳으로 바로 돌아왔습니다.다시 가리킬 수 없습니다.buffer새로운 allocated의 기억 속으로getline왜냐하면 우리는 오직 한 권의 복사본만 가지고 있기 때문입니다.buffer.


의 원형.getline실제로는 다음과 같습니다.

ssize_t
getline(char **lineptr, size_t *n, FILE *stream);

이렇게 부르시면 됩니다.

char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(&buffer, &len, stdin);

&buffer포인터를 에 반환합니다.buffer, 따라서 다음과 같은 것이 있습니다.

+-------+        +------+
|&buffer+------> +buffer+-------> NULL
+-------+        +---+--+

언제getline라고 합니다.lineptr등본을 보다&bufferC는 콜 바이 값이기 때문입니다.lineptr다음과 같은 위치를 가리킵니다.&buffer:

+-------+        +------+
|&buffer+------->+buffer+-------> NULL
+-------+        +---+--+
                     ^
+-------+            |
|lineptr+------------+
+-------+

getline메모리를 할당합니다.malloc의 요점을 가리키고 있습니다.lineptr(즉, 그 물건lineptr블록의 시작 부분에서 다음을 가리킵니다.

+-------+        +------+        +---+---+---+---+---+
|&buffer+------->+buffer+------->+   |   |   |   |   |
+-------+        +---+--+        +---+---+---+---+---+
                     ^
+-------+            |
|lineptr+------------+
+-------+

끝나고getline반품, 우리는 더 이상 접근할 수 없습니다.lineptr, 새 allocated 메모리에 접근할 수 있는 방법은buffer:

+-------+        +------+        +---+---+---+---+---+
|&buffer+------->+buffer+------->+   |   |   |   |   |
+-------+        +---+--+        +---+---+---+---+---+

왜냐면getline()Null 포인터에 포인터를 전달하면 메모리를 할당합니다.

맨 페이지에서:

getline ()는 스트림에서 전체 행을 읽고 텍스트가 포함된 버퍼의 주소를 *lineptr에 저장합니다.버퍼는 null-terminal 처리되며 새 줄 문자가 발견된 경우 새 줄 문자가 포함됩니다.

*lineptr이 NULL이면 getline()은 라인을 저장하기 위한 버퍼를 할당하며, 이 버퍼는 사용자 프로그램에 의해 해제되어야 합니다.(이 경우 *n의 값은 무시됩니다.)

당신은 통과해야 합니다.char**(즉, char의 포인터를 가리키는 포인터) 함수가 값을 업데이트할 수 있도록 합니다.char*그것이 가리키는 것.

다음을 사용할 수 있었습니다.

char *my_string = NULL;  // getline will alloc

puts("Please enter a line of text");

bytes_read = getline(&my_string, &nbytes, stdin);

만약 당신이 이렇게 한다면 당신이 책임져야 한다는 것을 잊지 마세요.free()-에 의해 할당된 메모리를 호출합니다.getline().

여기서부터 당신의 첫 번째 질문에 대한 답이 맞습니다.앞으로 manpage를 확인해보세요, 필요한 정보가 들어있습니다.

포인터가 초기화되지 않았기 때문에 두 번째 줄이 작동하지 않습니다.그렇게 하려면 다음과 같이 적어야 합니다.

char **my_string = malloc(sizeof(char**))

기본적으로 변수를 생성할 때 *는 포인터를 의미하고, 변수를 참조할 때는 포인터를 참조 해제합니다(포인터가 가리키는 것을 가져옵니다).& "이것을 가리키는 포인터"를 의미합니다.

새 공연에서 기존 코드를 넘겨받은 저는 calloc에 전화를 걸어 포인터를 돌려주지 않도록 주의를 기울여야 할 것 같습니다.작동해야 하지만 getline()의 작동 방식을 모호하게 합니다.& 연산자는 malloc(), calloc()에서 반환된 포인터의 주소를 전달하고 있음을 분명히 합니다.엄밀히 말하면 동일하지만, foo를 char *foo 대신 char **foo로 선언하고 getline(&foo, , ) 대신 getline(foo, , )이라고 부르는 것은 이 중요한 점을 모호하게 합니다.

  1. getline ()을 사용하면 저장소를 할당하고 malloc (), calloc ()가 반환하는 포인터에 대한 포인터를 getline ()에 전달할 수 있으며, 이 포인터를 포인터에 할당할 수 있습니다.예:

    char *foo = calloc(size_t arbitrarily_large, 1);

  2. 통과 가능합니다 &foo=NULL, 이 경우 보이지 않게 숨겨진 malloc(), calloc()를 조용히 호출하여 스토리지의 블라인드 할당을 수행합니다.

  3. char *foo, **p_foo=&foo도 가능합니다.그럼 foo = calloc(size_t, size_t)를 부른 다음 getline(p_foo,, ,; getline(&foo, , )이 더 나은 것 같습니다.

블라인드 할당은 매우 나쁘고, 문제가 있는 메모리에 대한 초대는 새어나갑니다. 코드 어디에도 malloc(), calloc()라고 부르지 않기 때문에, 사용자나 나중에 코드를 유지하는 임무를 맡은 사람은 해당 스토리지에 대한 포인터를 해제()할 수 없습니다.호출한 일부 함수는 사용자가 모르는 사이에 메모리를 할당하기 때문입니다(함수 설명을 읽고 블라인드 할당을 수행한다는 것을 이해하는 것을 제외하고).

getline()은 호출한 메모리를 malloc(), calloc()에 재할당()하므로 calloc()에 대한 호출과 함께 필요한 저장소에 대한 최선의 추측을 할당하고 포인터 char *foo가 무엇을 하는지 분명히 하는 것이 좋습니다.저는 getline()이 calloc()d만 있으면 스토리지로 어떤 것도 할 수 없다고 생각합니다.

새 스토리지가 힙의 다른 위치에 있을 수 있으므로 getline()이 realoc()을 호출하여 스토리지를 더 할당해야 하는 경우 포인터의 값이 변경될 수 있습니다.IE: &foo를 패스하고 foo의 주소가 12345이고 getline() realoc()이 저장소가 되고 새로운 위치에서 foo의 새로운 주소가 45678이 될 수 있습니다.

foo=를 설정하면 calloc (),에 직접 전화하는 것에 대한 논쟁이 아닙니다.NULL, getline()이 realoc()을 호출해야 합니다.

요약하면, 크기에 대한 좋은 추측과 함께 calloc()에 전화를 걸면 나중에 getline()이 무엇을 하든지 하지 않든지 간에 당신의 코드를 읽는 누구에게나 메모리가 무료()d로 할당되고 있다는 것이 분명해집니다.

if(NULL == line) {
     // getline() will realloc() if too small
    line = (char *)calloc(512, sizeof(char));
}
getline((char**)&line, (size_t *)&len, (FILE *)stdin);

함수 getline의 매개 변수로 char *lineptr 대신 char **lineptr을 사용하는 이유는 무엇입니까?

char **lineptr는 이유로 사용됩니다.getline()는 문자열을 저장할 위치를 가리키는 포인터의 주소를 요청합니다.
당신은 사용할 것입니다.char *lineptr한다면getline()포인터 자체가 예상됨(이는 작동하지 않음, This SuitIsBlackNot의 답변 이유 참조)

다음 코드를 사용할 때 잘못된 이유:
char **my_string; bytes_read = getline(my_string, &nbytes, stdin);

다음이 작동합니다.

char *my_string;
char **pointer_to_my_string = &my_string;
bytes_read = getline(my_string, &nbytes, stdin);

*와 &을 혼동하고 있습니다.

*이중적인 의미가 있습니다.
포인터 선언에 사용할 경우(예: char에 대한 포인터), 이는 char 대신 char에 대한 포인터를 원하는 것을 의미합니다.
다른 곳에서 사용하면 포인터가 가리키는 변수를 얻습니다.

&변수의 메모리에 저장된 주소를 가져옵니다(값으로 유지하도록 생성된 포인터).

char letter = 'c';
char *ptr_to_letter = &letter;
char letter2 = *ptr_to_letter;
char *ptr2 = &*ptr_to_letter; //ptr2 will also point to letter

&*ptr_to_letter주소를 알려주세요().&)의 값을 나타내는 변수입니다.ptr_to_letter점()*), 및 글 쓰는 것과 같음ptr_to_letter
생각할 수 있습니다.*과는 반대로&, 서로를 취소할 수 있을 겁니다

언급URL : https://stackoverflow.com/questions/5744393/why-is-the-first-argument-of-getline-a-pointer-to-pointer-char-instead-of-c

반응형