나는 두 구조를 만들어야하는 프로그래밍 운동을 가지고 Star
와 Cluster
. Star
이름, 첫 번째 숫자, 두 번째 숫자, 세 번째 숫자의 네 가지 인수를 가져야합니다. Cluster
n- 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
, 당신은 예를 들어, 다음 중 하나를 수행 할 수 :
struct Cluster
포인터를 포함하는 동적으로 할당의 첫 번째 요소를 가리키는 연결리스트 데이터 형식의 struct Star
.struct Cluster
배열을 포함하거나 회원 포인터가 해당 유형의 요소를 동적으로 할당 할 수 있었던 배열을 포인트한다 struct Star
. 이 배열의 요소 수를 추적하려면 별도의 멤버 변수가 추가로 필요합니다.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] 삭제
몇 마디 만하겠습니다