К сожалению, Вы не правильно поняли. Это была не
оценка, а
советы профессионала. Если честно, мне и лень, и неинтересно оценивать. Попытаться помочь, объяснить - дело другое.
Как научиться программировать - вопрос философский. Глупый ответ - из анекдота: "Как Вы печете такой вкусный хлеб? -- Очень просто. Мука, вода, немного соли, и тридцать лет у плиты.".
Я думаю, вопрос заслуживает отдельной темы. Начнете - я отвечу. Люблю, однако, провокации. А здесь дам только один совет, который вычитал в предисловии к книжке Вирта: читайте чужие программы, и пытайтесь понять их автора. Ну, и чтобы было проще следовать совету:
Код:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FILENAME "stars.dat"
#define STAR_ALLOC_SIZE 1000
#define MAX_NAME_SIZE 30
#define MAX_CLASS_SIZE 30
#define MAX_CONST_SIZE 30
#define MAX_MASS_SIZE 30
#define MAX_LINE_SIZE 128 // at least, sum of max sizes + separators + end-of-line
typedef struct star_type
{
char* Name;
float Mass;
char* Class;
char* Constellation;
} STAR;
typedef struct stars_list_type
{
int Num_stars; // actual numbe of stars in list
int Size; // capacity of the list
STAR** Stars;
} STAR_LIST;
// allocate memory for string and copy it
char* mkstr(char* s)
{
char* p;
p = (char*)malloc(strlen(s)+1);
if (p == NULL) {
return "*** error *** not enough memory";
} else {
strcpy(p, s);
return p;
}
}
// read a line from file - and flush unused portion
int getstr(FILE* f, char* buffer, size_t buffersz) {
char dummy[80];
char* p;
p = fgets(buffer, buffersz, f);
if (p == NULL) {
buffer[0] = 0;
return -1;
} else {
if (buffer[strlen(buffer)-1] == '\n') {
// delete end-of-line symbol
buffer[strlen(buffer)-1] = 0;
} else {
// flush rest of the line
while ((p != NULL) && (p[strlen(p)-1] != '\n')) {
p = fgets(dummy, sizeof(dummy), f);
}
}
return (int)strlen(buffer);
}
}
// read and check user selection
int get_choice(char* choices)
{
char buffer[3];
int ret_code;
ret_code = getstr(stdin, buffer, sizeof(buffer));
if (ret_code < 0) {
return ret_code;
} else if (strchr(choices, buffer[0]) == NULL) {
// char not found in choices
return 0;
} else {
// return user character
return buffer[0];
}
}
int compare_mass(const void* elem1, const void* elem2) {
STAR* s1 = *(STAR**) elem1;
STAR* s2 = *(STAR**) elem2;
if (s1->Mass < s2->Mass) {
return -1;
} else if (s1->Mass > s2->Mass) {
return 1;
} else {
return 0;
}
}
int compare_name(const void* elem1, const void* elem2) {
STAR* s1 = *(STAR**) elem1;
STAR* s2 = *(STAR**) elem2;
return strcmp(s1->Name, s2->Name);
}
int compare_constellation(const void* elem1, const void* elem2) {
STAR* s1 = *(STAR**) elem1;
STAR* s2 = *(STAR**) elem2;
int cmp;
cmp = strcmp(s1->Constellation, s2->Constellation);
if (cmp != 0) {
// different constellations
return cmp;
} else {
// the same constellation, sorting by name
return strcmp(s1->Name, s2->Name);
}
}
void add_star(STAR_LIST* star_list, char* name, float mass, char* class_, char* constellation)
{
STAR* new_star;
new_star = (STAR*)malloc(sizeof(STAR));
if (new_star == NULL)
{
printf("*** error *** not enough memory");
return;
}
new_star->Name = mkstr(name);
new_star->Mass = mass;
new_star->Class = mkstr(class_);
new_star->Constellation = mkstr(constellation);
if (star_list->Num_stars >= star_list->Size)
{
star_list->Size += STAR_ALLOC_SIZE;
star_list->Stars = (STAR**)realloc(star_list->Stars, (star_list->Size) * sizeof(*(star_list->Stars)));
}
star_list->Stars[star_list->Num_stars] = new_star;
++star_list->Num_stars;
}
void read_from_file(char* filename, STAR_LIST* star_list)
{
FILE* f;
char line[MAX_LINE_SIZE];
char *name, *class_, *constellation, *mass_str, *separator_ptr;
float mass;
f = fopen(filename, "r");
if (f == NULL) {
printf("*** error *** cannot open file '%s' for reading\n\n", filename);
return;
}
while (!feof(f))
{
getstr(f, line, sizeof(line));
name = line;
separator_ptr = strchr(name, ';');
if (separator_ptr == NULL) continue;
*separator_ptr = 0;
mass_str = separator_ptr + 1;
separator_ptr = strchr(mass_str, ';');
if (separator_ptr == NULL) continue;
*separator_ptr = 0;
mass = (float) atof(mass_str);
class_ = separator_ptr + 1;
separator_ptr = strchr(class_, ';');
if (separator_ptr == NULL) continue;
*separator_ptr = 0;
constellation = separator_ptr + 1;
separator_ptr = strchr(constellation, ';');
if (separator_ptr == NULL) continue;
*separator_ptr = 0;
add_star(star_list, name, mass, class_, constellation);
}
fclose(f);
}
void print_star(STAR* star)
{
printf("--- %s ---\n", star->Name);
printf("\t%f Msun\tClass: %s\tConstellation: %s\n", star->Mass, star->Class, star->Constellation);
}
void show_contents(STAR_LIST* star_list)
{
int i;
for (i = 0; i < star_list->Num_stars; i++) {
print_star(star_list->Stars[i]);
}
}
void add_new_star(STAR_LIST* star_list)
{
char name[MAX_NAME_SIZE], class_[MAX_CLASS_SIZE], constellation[MAX_CONST_SIZE], mass_str[MAX_MASS_SIZE];
float mass;
printf("Name of star: ");
getstr(stdin, name, sizeof(name));
printf("Mass of star: ");
getstr(stdin, mass_str, sizeof(mass_str));
mass = (float)atof(mass_str);
printf("Class: ");
getstr(stdin, class_, sizeof(class_));
printf("Constellation: ");
getstr(stdin, constellation, sizeof(constellation));
add_star(star_list, name, mass, class_, constellation);
}
void correct_star(STAR_LIST* star_list)
{
int i, num;
char name[MAX_NAME_SIZE], class_[MAX_CLASS_SIZE], constellation[MAX_CONST_SIZE], mass_str[MAX_MASS_SIZE];
char num_str[10];
for (i = 0; i < star_list->Num_stars; i++)
{
printf("%6d) %-*s ", i+1, MAX_NAME_SIZE, star_list->Stars[i]->Name);
if (i % 2 == 1)
{
putchar('\n');
}
}
printf("\nWhat's the stars number you want to edit?: ");
getstr(stdin, num_str, sizeof(num_str));
num = atoi(num_str);
if ((num < 1) || (num >= star_list->Num_stars)) {
printf("*** error *** selection incorrect (%s)", num_str);
return;
}
--num;
print_star(star_list->Stars[num]);
puts("Want to correct:");
puts("The name.............1");
puts("The mass.............2");
puts("The class............3");
puts("The constellation....4");
putchar('>');
switch (get_choice("1234"))
{
case '1':
printf("Name of star: ");
getstr(stdin, name, sizeof(name));
free(star_list->Stars[num]->Name);
star_list->Stars[num]->Name = mkstr(name);
break;
case '2':
printf("Mass of star: ");
getstr(stdin, mass_str, sizeof(mass_str));
star_list->Stars[num]->Mass = (float) atof(mass_str);
break;
case '3':
printf("Class: ");
getstr(stdin, class_, sizeof(class_));
free(star_list->Stars[num]->Class);
star_list->Stars[num]->Class = mkstr(class_);
break;
case '4':
printf("Constellation: ");
getstr(stdin, constellation, sizeof(constellation));
free(star_list->Stars[num]->Constellation);
star_list->Stars[num]->Constellation = mkstr(constellation);
break;
default:
printf("no correction done...\n");
break;
}
}
void write_to_file(char* filename, STAR_LIST* star_list)
{
FILE* f;
int i;
f = fopen(filename, "w");
if (f == NULL) {
printf("*** error *** cannot open file '%s' for writing\n\n", filename);
return;
}
for (i = 0; i < star_list->Num_stars; i++)
{
fprintf(f, "%s;%f;%s;%s;\n",
star_list->Stars[i]->Name, star_list->Stars[i]->Mass, star_list->Stars[i]->Class,
star_list->Stars[i]->Constellation);
}
fclose(f);
}
void init_star_list(STAR_LIST* star_list)
{
star_list->Num_stars = 0;
star_list->Size = 0;
star_list->Stars = NULL;
}
void destroy_star_list(STAR_LIST* star_list)
{
int k;
for (k = 0; k < star_list->Num_stars; ++k) {
free(star_list->Stars[k]->Name);
free(star_list->Stars[k]->Class);
free(star_list->Stars[k]->Constellation);
free(star_list->Stars[k]);
}
free(star_list->Stars);
init_star_list(star_list);
}
void main()
{
STAR_LIST star_list;
int choice;
init_star_list(&star_list);
read_from_file(FILENAME, &star_list);
for (;;)
{
puts("\nShow contents of the file.....1");
puts("Add a star....................2");
puts("Correct data of a star........3");
puts("Order by mass.................4");
puts("Order by name.................5");
puts("Order by constallation........6");
puts("Quit..........................x");
putchar('>');
choice = get_choice("123456xX");
if ((choice == -1) || (choice == 'x') || (choice == 'X')) {
// end-of-file on input, or user command
break;
}
switch (choice)
{
case 0:
// invalid input
break;
case '1':
// just show contents
show_contents(&star_list);
break;
case '2':
// add a new star and save file
add_new_star(&star_list);
write_to_file(FILENAME, &star_list);
break;
case '3':
// edit star definition and save file
correct_star(&star_list);
write_to_file(FILENAME, &star_list);
break;
case '4':
// sort list by star mass and display it
qsort(star_list.Stars, star_list.Num_stars, sizeof(*star_list.Stars), compare_mass);
show_contents(&star_list);
break;
case '5':
// sort list by star name and display it
qsort(star_list.Stars, star_list.Num_stars, sizeof(*star_list.Stars), compare_name);
show_contents(&star_list);
break;
case '6':
// sort list by constellation and display it
// and by name in the same constellation
qsort(star_list.Stars, star_list.Num_stars, sizeof(*star_list.Stars), compare_constellation);
show_contents(&star_list);
break;
}
}
destroy_star_list(&star_list);
}
Я пытался оставить Ваш код узанаваемым для Вас. GCC может не понимать коментарии в стиле C++ (//), тогда их прдется заменить на /* */. Обратите внимение на служебные функции. Их должно быть еще большею Например, ввод имени звезды встречается в двух местах, а преобразование массы из строки - в трех. Кроме того, мне не очевидно, не следует ли хранить массу в числовом и строковом виде - поскольку преобразование
строка (в файле) -> число (в программе) -> строка в файле не гарантирует неизменность числа. Обратите внимание на метод захвата памяти для списка звезд - большими кусками. И еще, при редактрровании
ни в коем случае нельзя читать в старые буфера. Новое имя может просто оказаться длинее, и что тогда?
И главное - не стесняйтесь задавать вопросы! Очень надеюсь, их будет много. И они не иссякнут после сдачи...