c의 중첩 된 구조체, 포인터 주소 지정 문제

콘라드

나는 두 구조를 만들어야하는 프로그래밍 운동을 가지고 StarCluster. Star이름, 첫 번째 숫자, 두 번째 숫자, 세 번째 숫자의 네 가지 인수를 가져야합니다. Clustern- stars.dat 파일에있는 별 별이있는 파일 이름에 대한 정보를 포함합니다. 그런 다음 파일을 인수로 취하고 파일 Cluster에서 읽은 구조에 대한 포인터를 리턴하는로드 함수를 작성 하십시오. 내 코드는 다음과 같습니다.

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

#define MAX_NAME 100

struct Star {
    char name[MAX_NAME];
    double recta;
    double decl;
    double mag;
};

struct Cluster {
    struct Star *ptr;
    char *file;
};

struct Cluster *load(char *plik);

int main() {
    load("stars.dat");
    return 0;
}

struct Cluster *load(char *plik) {
    char line[MAX_NAME];
    int i = 0;
    struct Star *star_ptr;

    FILE *file = fopen(plik, "r");
    struct Cluster *cluster_ptr;
    if (!plik) {
        perror(plik);
        exit(-1);
    } else {
        while (fgets(line, MAX_NAME, file) != NULL) {
            star_ptr = malloc(sizeof(struct Star));
            sscanf(line, "%s %lf %lf %lf", star_ptr->name, &star_ptr->recta, &star_ptr->decl, &star_ptr->mag);

            printf("%s \n", star_ptr->name);
            star_ptr++;
            i++;
        }
        cluster_ptr = (struct Cluster *)malloc(sizeof(struct Star) * i);
        cluster_ptr->ptr = star_ptr;
        cluster_ptr->file = plik;
        // printf("%s \n", cluster_ptr->star_ptr[0].name);
        printf("%s \n", star_ptr[0].name);
    }
    fclose(file);
    return cluster_ptr;
}

내 질문은 이것이 적절한 방법인지 여부입니다. 반환 된 포인터가 좋은지 어떻게 확인할 수 있습니까 ( printf예를 들어 목록에서 첫 번째 별의 이름을 찾는 방법을 알 수 없습니다 ). 누군가 나에게 힌트를 줄 수 있다면 고맙겠습니다.

안드레아스 웬젤

struct Cluster멤버 변수 처리가 struct Star *ptr의미가 없습니다.

당신이 원하는 경우 struct Cluster복수 "를 포함"할 수 있도록 struct Star, 당신은 예를 들어, 다음 중 하나를 수행 할 수 :

  1. 확인 struct Cluster포인터를 포함하는 동적으로 할당의 첫 번째 요소를 가리키는 연결리스트 데이터 형식의 struct Star.
  2. 확인 struct Cluster배열을 포함하거나 회원 포인터가 해당 유형의 요소를 동적으로 할당 할 수 있었던 배열을 포인트한다 struct Star. 이 배열의 요소 수를 추적하려면 별도의 멤버 변수가 추가로 필요합니다.
  3. 확인 struct Cluster배열을 포함하거나 부재 포인터가 그 유형의 요소를 동적으로 할당 된 어레이에 대한 포인트 struct Star*의 각 요소는 동적으로 할당 된 자신의 포인터이다 struct Star. 이 배열의 요소 수를 추적하기 위해 요소 수를 지정하는 별도의 변수를 갖거나 NULL포인터 와 같은 특수 값으로 배열의 끝을 표시 할 수 있습니다.

코드는 이러한 옵션을 모두 수행하지 않습니다. 대신 다음을 수행합니다.

파일에서 찾은 모든 별에 대해 하나의 단일에 대해 충분한 메모리를 동적으로 할당 struct Star합니다. 그러나 this의 메모리 주소를 기억하는 대신 struct Star루프의 다음 반복에서이 메모리 주소에 대한 포인터를 next의 메모리 주소로 덮어 쓰므로 struct Star더 이상 첫 번째의 주소를 알 수 없습니다 struct Star. 이것은 메모리 누수 입니다. 루프의 마지막 반복이 완료되면 클러스터의 ptr구성원 struct Star이 할당 된 마지막 가리 키도록하여 효과적으로 하나의 별만 가리 키도록합니다. 내가 이미 지적했듯이 당신은 그들의 기억 위치를 기억하지 못했기 때문에 더 많은 별을 가리킬 수 없습니다.

따라서 문제를 해결하려면 위에 나열된 옵션 중 사용하려는 옵션을 결정하고 그에 따라 코드를 작성하는 것이 좋습니다. 클러스터의 별 수를 미리 알지 못하는 경우 먼저 옵션 # 1 (연결 목록)을 시도하는 것이 좋습니다.

또한 다음 줄에는 버그가 있습니다.

if (!plik)

다음과 같이 변경해야합니다.

if (!file)

또는 내가 개인적으로 더 읽기 쉽다고 생각하는 이것에 대해 :

if ( file == NULL )

편집 : 연결 목록 구현에 대한 예제를 원한다고 주석 섹션에서 언급 했으므로 그에 따라 코드를 수정하고 아래에 게시했습니다.

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

//Do not change the following line without also changing MAX_NAME_MINUS_ONE_STRING
#define MAX_NAME 100
#define MAX_NAME_MINUS_ONE_STRING "99"
//the line above must have the value MAX_NAME - 1 and be enclosed in quotation
//marks, otherwise you risk a buffer overflow in the sscanf function call!

struct StarNode
{
    //this points to the next node of the linked list
    struct StarNode *next;

    //I changed this struct member to a pointer to a dynamically
    //allocated string, because having a char array of 100 bytes
    //was a waste of memory
    char *name;

    double recta;
    double decl;
    double mag;
};

struct Cluster
{
    //points to the head of the linked list of stars
    struct StarNode *p_head;

    //points to its own dynamically allocated copy of the filename
    char *filename;
};

struct Cluster* load_cluster( const char* filename );
void cleanup_cluster( struct Cluster *p_cluster );

int main()
{
    struct Cluster *cluster_ptr;

    cluster_ptr = load_cluster( "stars.dat" );

    cleanup_cluster( cluster_ptr );

    return 0;
}

struct Cluster* load_cluster( const char *filename )
{
    char line[MAX_NAME];

    //pp_next will always point to the address of the struct StarNode * where
    //the address of the next node should be written
    struct StarNode *p_newstar, **pp_next;
    struct Cluster *p_cluster;

    FILE *file = fopen( filename, "r" );
    assert( file != NULL );

    p_cluster = (struct Cluster*)malloc( sizeof( struct Cluster ) );
    assert( p_cluster != NULL );

    pp_next = &p_cluster->p_head;

    while ( fgets( line, MAX_NAME, file ) != NULL )
    {
        char starname[MAX_NAME];
        int i;

        p_newstar = (struct StarNode *)malloc( sizeof( struct StarNode ) );
        assert( p_newstar != NULL );

        //I changed the %s to %99s (assuming MAX_NAME == 100) to prevent buffer overflow.
        //The value must be one less in order to have space for the null terminator.
        //Also, I now check the return value of sscanf.
        i = sscanf( line, "%" MAX_NAME_MINUS_ONE_STRING "s %lf %lf %lf", starname, &p_newstar->recta, &p_newstar->decl, &p_newstar->mag );
        assert( i == 4 );

        printf( "Adding %s\n", starname );

        //allocate memory for star's own copy of starname and copy it
        p_newstar->name = (char*)malloc( strlen( starname ) + 1 /*for null terminator character*/ );
        assert( p_newstar->name != NULL );
        strcpy( p_newstar->name, starname );

        //link the new star node to the linked list
        *pp_next = p_newstar;

        //update pp_next to the address of the pointer where the address of the next node should be written to
        pp_next = &p_newstar->next;
    }

    //the last element of the linked list must have a NULL pointer
    *pp_next = NULL;

    //allocate sufficient memory for filename and copy the string
    p_cluster->filename = (char*)malloc( strlen( filename ) + 1 /*for null terminator character*/ );
    assert( p_cluster->filename != NULL );
    strcpy( p_cluster->filename, filename );

    fclose( file );
    return p_cluster;
}


void cleanup_cluster( struct Cluster *p_cluster )
{
    struct StarNode *p;

    p = p_cluster->p_head;

    //cleanup every star node individually
    while ( p != NULL )
    {
        struct StarNode *temp;

        printf( "Deleting %s\n", p->name );
        free( p->name );

        temp = p;
        p = p->next;
        //free must be called last, because the contents of the current node become invalid
        //once free is called, which means that also the pointer to the next node would
        //become invalid
        free( temp );
    }

    free( p_cluster->filename );

    free( p_cluster );
}

위의 코드에서는 cleanup_cluster클러스터에서 할당 한 메모리를 해제하기 위해 함수도 만들었습니다 .

나는 또한 라인을 변경했습니다

cluster_ptr->file = plik;

클러스터 구조체가 자체 문자열 사본을 저장하도록합니다. 이것은 포인터가 매달린 포인터 가되지 않고 제한된 수명 (예 : 로컬 char 배열)을 가진 문자열을 함수에 전달할 수도 있다는 장점이 있습니다 .

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

"경고 : 포인터와 정수 간의 비교"라고 말하는 C의 중첩 된 구조체

분류에서Dev

c에 정의 된 구조체에 대한 Swift 정의 이중 포인터

분류에서Dev

중첩 된 구조체의 멤버 변수에 대한 포인터

분류에서Dev

중첩 된 구조체의 멤버 변수에 대한 포인터

분류에서Dev

C에서 중첩 된 구조체 포인터에 대한 코드 생성

분류에서Dev

중첩 된 주석의 이해 구조 / 구문

분류에서Dev

중첩 된 구성 요소에서 단락 태그 스타일 지정 문제

분류에서Dev

구조체의 포인터 문제

분류에서Dev

C에서 구조체없이 중첩 된 이중 포인터를 갖는 방법은 무엇입니까?

분류에서Dev

중첩 된 데이터 구조에서 요소 제거

분류에서Dev

중첩 된 개체의 개조 구문 분석

분류에서Dev

중첩 된 내부 조인 문제

분류에서Dev

C ++ 포인터로 함수에 전달 된 구조체 수정

분류에서Dev

C ++ protobuf 중첩 된 구조체의 값을 설정하는 방법

분류에서Dev

창 크기 조정시에만 div 중첩 방지 (스타일이 지정된 구성 요소 포함)

분류에서Dev

C 언어 : 중첩 된 구조체에서 문자 배열 참조

분류에서Dev

C 언어 : 중첩 된 구조체에서 문자 배열 참조

분류에서Dev

주소를 참조하지 않고 주소와 C ++ 포인터

분류에서Dev

중첩 된 그리드 표시 문제의 Material UI React 종이 구성 요소

분류에서Dev

void **로 캐스트 된 이중 포인터의 주소

분류에서Dev

문자열이 특정 길이에 도달하면 구조체의 문자 포인터 요소를 해제 할 수 없습니다.

분류에서Dev

개체 주소 지정 / 액세스 문제 내의 C # 목록

분류에서Dev

다른 구조체의 첫 번째 정의로 중첩 된 구조체는 오프셋이 0입니까?

분류에서Dev

c의 중첩 된 구조체 / 연결된 목록

분류에서Dev

가변 인수로 함수를 정의하기 위해 중첩 된 #define 문제

분류에서Dev

역 참조 된 포인터와 구조체 사용의 STM32F446xx 주변 레지스터 액세스 차이점

분류에서Dev

주소가 지정된 포인터의 대괄호는 무엇입니까?

분류에서Dev

구조체 배열에 중첩 된 구조체 배열을 정렬하는 방법 C

분류에서Dev

이것이 다른 구조체에 중첩 된 구조체에서 왔을 때 malloc char 포인터

Related 관련 기사

  1. 1

    "경고 : 포인터와 정수 간의 비교"라고 말하는 C의 중첩 된 구조체

  2. 2

    c에 정의 된 구조체에 대한 Swift 정의 이중 포인터

  3. 3

    중첩 된 구조체의 멤버 변수에 대한 포인터

  4. 4

    중첩 된 구조체의 멤버 변수에 대한 포인터

  5. 5

    C에서 중첩 된 구조체 포인터에 대한 코드 생성

  6. 6

    중첩 된 주석의 이해 구조 / 구문

  7. 7

    중첩 된 구성 요소에서 단락 태그 스타일 지정 문제

  8. 8

    구조체의 포인터 문제

  9. 9

    C에서 구조체없이 중첩 된 이중 포인터를 갖는 방법은 무엇입니까?

  10. 10

    중첩 된 데이터 구조에서 요소 제거

  11. 11

    중첩 된 개체의 개조 구문 분석

  12. 12

    중첩 된 내부 조인 문제

  13. 13

    C ++ 포인터로 함수에 전달 된 구조체 수정

  14. 14

    C ++ protobuf 중첩 된 구조체의 값을 설정하는 방법

  15. 15

    창 크기 조정시에만 div 중첩 방지 (스타일이 지정된 구성 요소 포함)

  16. 16

    C 언어 : 중첩 된 구조체에서 문자 배열 참조

  17. 17

    C 언어 : 중첩 된 구조체에서 문자 배열 참조

  18. 18

    주소를 참조하지 않고 주소와 C ++ 포인터

  19. 19

    중첩 된 그리드 표시 문제의 Material UI React 종이 구성 요소

  20. 20

    void **로 캐스트 된 이중 포인터의 주소

  21. 21

    문자열이 특정 길이에 도달하면 구조체의 문자 포인터 요소를 해제 할 수 없습니다.

  22. 22

    개체 주소 지정 / 액세스 문제 내의 C # 목록

  23. 23

    다른 구조체의 첫 번째 정의로 중첩 된 구조체는 오프셋이 0입니까?

  24. 24

    c의 중첩 된 구조체 / 연결된 목록

  25. 25

    가변 인수로 함수를 정의하기 위해 중첩 된 #define 문제

  26. 26

    역 참조 된 포인터와 구조체 사용의 STM32F446xx 주변 레지스터 액세스 차이점

  27. 27

    주소가 지정된 포인터의 대괄호는 무엇입니까?

  28. 28

    구조체 배열에 중첩 된 구조체 배열을 정렬하는 방법 C

  29. 29

    이것이 다른 구조체에 중첩 된 구조체에서 왔을 때 malloc char 포인터

뜨겁다태그

보관