2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2, 3, 4, 5 ... 7  След.
 
 База данных на С.
Сообщение13.11.2005, 17:07 
Заслуженный участник


28/10/05
1368
Подкинули задачу. Времени дали неделю. Постараюсь сделать сама. Если успею и кто-то проверит - спасибо, если кто-то напишет и надо будет просто разобраться, то это еще проще. Потому что я все равно этим заниматься не буду. Это чтобы проверить, что я что-то делать умею.

Нужно написать программу, которая позволяет создавать и управлять небольшой базой данных звезд.

Программа должна регистрировать для каждой звезды следующую информацию:
1. Название звезды. (Будут использоваться обозначения Байера, в которых греческие буквы пишутся как в теге [math]. Например: Eta Carinae.)
2. Масса. (Единица измерения - масса Солнца - 1.9891 x 10^30 кг)
3. Класс звезды(Согласно спектральной классификации Моргана-Кинана. Эта классификация начинается с буквы, за которой следуют однозначные числа и буквы, которые обозначают вторичную классификацию. Например: Epsilon Orionis имеет классификацию B0 Ia.)
4. Cозвездие, к которому принаджлежит звезда.

В Википедии есть список звезд. В этом списке ссылки дают информацию о каждой отдельной звезде.

При запуске программа должна читать содержимое файла stars.dat и заполнять таблицу данными. Далее программа должна показывать следующее меню:

Код:
> stars
Show contents of the table...1
Add a star...................2
Correct data of a star.......3
Order by mass................4
Order by name................5
Order by constellation.......6
Quit.........................x


Файл имеет свободный формат, но посоветовали пользоваться таким:

Код:
field1;field2;field3;
field1;field2;field3;


Каждая строка содержит информацию о звезде. В строке разные поля отделяются точкой с запятой.

Например файл может быть:
Код:
Epsilon Orionis;20.000000;B0 Ia;Orion;
Eta Cassiopeiae;0.000000;G3 V;Cassiopeia;
Sol;1.000000;?;?;
Epsilon Indi;0.770000;K5 Ve;Indus;
Eta Carinae;150.000000;?;Carina;
Alpha Aquilae;1.700000;A7 IV-V;Aquila;


Первая "опция" меню должна показывать следующее содержание, используя такой формат:

Код:
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x
> 1
--- Epsilon Orionis ---
20.00 Msun Class: B0 Ia Constellation: Orion
--- Eta Cassiopeiae ---
  0.00 Msun Class: G3 V Constellation: Cassiopeia
--- Sol ---
  1.00 Msun Class: ? Constellation: ?
--- Epsilon Indi ---
  0.77 Msun Class: K5 Ve Constellation: Indus
--- Eta Carinae ---
150.00 Msun Class: ? Constellation: Carina
--- Alpha Aquilae ---
  1.70 Msun Class: A7 IV-V Constellation: Aquila


Неизвестные сведения заменяются на "?".
Вторая опция меню позволяет добавить звезду. Программа просит ввести данные и новая звезда добавляется к списку:

Код:
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x
> 2
Name of star: Beta Tauri
Mass of star: 0
Class: B7
Constellation: Taurus


Oпция 3 позволяет исправлять информацию о звезде. Когда выбирается эта опция, программа должна показывать список звезд (только названия, по три в строке) и просит выбрать звезду, данные о которой надо изменить:

Код:
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x
3
0) Epsilon Orionis 1) Eta Cassiopeiae 2) Sol
3) Epsilon Indi 4) Eta Carinae 5) Alpha Aquilae
6) Beta Tauri 
What´s the star´s number you want to edit? 6


Как только номер звезды выбран, программа должна показывать данные звезды и спрашивает, какую область "field" надо исправить:
Код:
--- Beta Tauri ---
  0.00 Msun Class: B7 Constellation: Taurus
Want to correct:
The name ...........1
The mass ...........2
The class ..........3
The constellation...4
> 2
Mass of the star: 4.7
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x


Три последующие опции позволяют расположить таблицу звезд согласно разным критериям. Расположение по массе показывает звезды в порядке убывания массы. Расположение по имени и по созвездию - в "растущем" алфавитном порядке. Тут надо использовать функцию qsort стандартной библиотеки С (stdlib.h). Вот так должна выглядеть таблица звезд, расположенные по массе.

Код:
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x
1
--- Epsilon Orionis ---
20.00 Msun Class: B0 Ia Constellation: Orion
--- Eta Cassiopeiae ---
  0.00 Msun Class: G3 V Constellation: Cassiopeia
--- Sol ---
  1.00 Msun Class: ? Constellation: ?
--- Epsilon Indi ---
  0.77 Msun Class: K5 Ve Constellation: Indus
--- Eta Carinae ---
150.00 Msun Class: ? Constellation: Carina
--- Alpha Aquilae ---
  1.70 Msun Class: A7 IV-V Constellation: Aquila
--- Beta Tauri ---
  4.70 Msun Class: B7 Constellation: Taurus
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x
4
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x
1
--- Eta Carinae ---
150.00 Msun Class: ? Constellation: Carina
--- Epsilon Orionis ---
20.00 Msun Class: B0 Ia Constellation: Orion
--- Beta Tauri ---
  4.70 Msun Class: B7 Constellation: Taurus
--- Alpha Aquilae ---
  1.70 Msun Class: A7 IV-V Constellation: Aquila
--- Sol ---
  1.00 Msun Class: ? Constellation: ?
--- Epsilon Indi ---
  0.77 Msun Class: K5 Ve Constellation: Indus
--- Eta Cassiopeiae ---
  0.00 Msun Class: G3 V Constellation: Cassiopeia
Show contents of the file...1
Add a star..................2
Correct data of a star......3
Order by mass...............4
Order by name...............5
Order by constellation......6
Quit........................x


Должно содержать программный файл stars.c ; файл данных stars.dat .
Я думаю, количество звезд не важно.

Ecли кто-то досмотрел до этого момента и еще не заснул, и знает, что конкретно нужно уметь делать, то подскажите. Я буду пока читать pointers. Мне так кажется, это чуть ли не стандартная программа для любого, кто учится на прогр. Я не права?

И еще осмелюсь посоветовать. Не ходите по воскресеньям гулять в парк. Иногда там встречаются научн. рук. Точнее еще выше по иерархической лестнице, типа завед. И никто гарантии не даст, что у него в портфеле нет для Вас :( сюрприза.

 Профиль  
                  
 
 
Сообщение13.11.2005, 20:01 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
1) Почитайте (если еще не читали) описание функции strtok() из стандартной библиотеки. Почему-то в учебниках не встречается, и (по-видимому, из-за этого) неизвестна большинству практиков. Она решит полностью проблемы разбора строки на поля. Имейте ввиду, она преобразует исходный буфер, и, если он используется повторно (например, в него читают новую строку), эти указатели будут показывать в середину чего-то.

2) Будьте очень осторожны с размерами буферов и функциями ввода. Именно там легко может произойти неявное (не в Вашей программе) и потому особо опасное переполнение. Лучше пользоваться функциями, где размер буфера явно указывается.

3) Если программа учебная, то один из вариантов - плевать на все, и читать весь файл в память за раз. Размер файла легко прочесть с диска. Потом отводим буфер нужного размера (1 в запасе на 0-терминатор) - один на всех. Читаем файл за одно чтение (длина-то известна). Делим на строки при помощи strtok(). Делим строки на поля при помощи strtok(). Все. Осталось только написать меню и вывод. Но ввод окажется до смешного коротким и простым. Здесь самое подлое место - количество строк в файле. Отводите динамически, и, при переполнении, пользуйтесь realloc().

 Профиль  
                  
 
 
Сообщение13.11.2005, 22:24 
Заслуженный участник


28/10/05
1368
Зачем понадобилась эта программа - понятия не имею. Этот человек не занимается никакими звездами. Разве что не ему лично или он просто решил меня включить в группу, которая не только на бумаге пишет, но и по клавиатуре стучит, а для этого надо подучиться.

Коли Вы знаете, что есть, а чего нет в учебниках, посоветуйте путевые книги и где можно взять. Потому что у меня только один учебник, хоть, кажется, и не плохой.

 Профиль  
                  
 
 
Сообщение13.11.2005, 22:53 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Извините, но вот с этим помочь не могу. Надеюсь, другие подскажут.

Если честно, я воспринимаю задачу исключительно как учебную. Писать сегодня на C физику - вредно и глупо. Простите за сарказм, но можно еще машинные коды - нет, не ассемблер, а именно коды - повводить. Желательно с пульта на тумблерах. Я всегда рекомендую Python как метод решения проблем. Снимает массу головных болей. Если я правильно знаю, входит почти во все дистрибутивы Linux'а.

Я не видел хороших учебников C. Керниган и Ричи безнадежно устарели, как в смысле языка, так и в смысле хорошего тона программирования. Рекомендовать Вам читать Стандарт - глупо. Не это Вам нужно, и я это понимаю. А хорошие преподователи, вроде Вирта, предпочитают с C не связываться.

Имейте в виду, что с С язык - это полдела. Вторая бОльшая половина - это стандартная библиотека, решающая очень многие проблемы за автора программы. Но ей учебники обычно уделяют меньшее место ("эта книга посвящена языку C"). Поэтому, выбирая книжку, обратите внимание на освещение библиотеки (особливо управление памятью, i/o, и обработка строк). Это съэкономит Вам массу времени и кода.

 Профиль  
                  
 
 
Сообщение13.11.2005, 23:10 
Заслуженный участник


28/10/05
1368
Oтож, strtok() в моей книге и правда нет. Зато я нашла вот это. Мне как-то хоть С, хоть FORTRAN, хоть.. - один черт. Лишь бы дальше в этом копаться не заставили.
Цитата:
Писать сегодня на C физику - вредно и глупо.

Смотря что писать. Под какие-то эксперименты можно. Я такое слышала.

Все же если кто-то знает порядочную литературу, напишите пожалуйста. Я со всем, что издано на русском языке, не знакома.

 Профиль  
                  
 
 
Сообщение14.11.2005, 02:32 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
http://www.opengroup.org/onlinepubs/009695399/toc.htm
- это, формально, не библиотека C. Но расхождений я ни разу не нашел. Покрывает очень многое... Просто редкостный по качеству и глубине ресурс.

 Профиль  
                  
 
 
Сообщение15.11.2005, 11:35 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
Точно не на C++, а просто на C? Спрашиваю потому что на C тяжеловато идет... Такое очучение, как будто руки связали... :)

 Профиль  
                  
 
 
Сообщение15.11.2005, 12:59 
Заслуженный участник


28/10/05
1368
Sanyok писал(а):
Точно не на C++, а просто на C? Спрашиваю потому что на C тяжеловато идет... Такое очучение, как будто руки связали... :)


Cогласна. "А вы работайте, товарищи, работайте..." :) Как-то оно будет. Напишу письмо турецкому султану.
Но тут порешили, что программка учебная, значит так и должно быть. Для лучшего усвоения материала С.

 Профиль  
                  
 
 
Сообщение15.11.2005, 14:05 
Заслуженный участник
Аватара пользователя


12/10/05
478
Казань
И еще такой вопрос: файл, откуда читаем, обязательно должен существовать заранее? Как быть, если его сначала нет? И нужно ли по выходе из проги сохранять изменения в файле (например, туда звезду добавили или что-то изменили)? Просто если не сохранять, то все это теряет смысл... Потому как прога должна что-то делать, даже если она и учебная... :)

 Профиль  
                  
 
 
Сообщение15.11.2005, 18:28 


13/09/05
153
Москва
Все это дело можно легко сделать на STL - использовать std::vector для хранения данных, std::string для хранения строк и std::sort - для сортировки. Тогда основные функции будут что-то типа этого -
Код:
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>

struct star_data
{
   std::string name;
   double mass;
   std::string class_name;
   std::string parent_name;
};

bool read_data(std::string file_name, std::vector<star_data*>& data_vector)
{
   std::ifstream InputFile(file_name.c_str());
   if (InputFile.fail())
      return false;
   while (!InputFile.eof() && !InputFile.fail())
   {
      std::string str;
      std::getline(InputFile, str, '\n');
      if (str.length() == 0)
         break;
//   Используем в качестве разделителя символ табуляции \t -
      int nPos1 = str.find('\t', 0);
      int nPos2 = str.find('\t', nPos1 + 1);
      int nPos3 = str.find('\t', nPos2 + 1);
      int nPos4 = str.find('\t', nPos3 + 1);
      std::string str1 = str.substr(0, nPos1);
      std::string str2 = str.substr(nPos1 + 1, nPos2 - nPos1 - 1);
      std::string str3 = str.substr(nPos2 + 1, nPos3 - nPos2 - 1);
      std::string str4 = str.substr(nPos3 + 1, str.length() - nPos3);
      star_data* data = new star_data;
      data->name = str1;
      data->mass = atof(str2.c_str());
      data->class_name = str3;
      data->parent_name = str4;
      data_vector.push_back(data);
   }
   InputFile.close();
   return true;   
}

bool write_data(std::string file_name, std::vector<star_data*>& data_vector)
{
   std::ofstream OutputFile(file_name.c_str());
   if (OutputFile.fail())
      return false;
   for (std::vector<star_data*>::iterator iter = data_vector.begin(); iter != data_vector.end(); iter++)
   {
      OutputFile << (*iter)->name.c_str() << "\t";
      OutputFile << (*iter)->mass << "\t";
      OutputFile << (*iter)->class_name.c_str() << "\t";
      OutputFile << (*iter)->parent_name.c_str() << std::endl;
   }
   OutputFile.close();
   return true;
}

bool compare_name(star_data* data1, star_data* data2)
{
   return data1->name < data2->name;
}

bool compare_mass(star_data* data1, star_data* data2)
{
   return data1->mass < data2->mass;
}

bool compare_class_name(star_data* data1, star_data* data2)
{
   return data1->class_name < data2->class_name;
}

bool compare_parent_name(star_data* data1, star_data* data2)
{
   return data1->parent_name < data2->parent_name;
}

void sort_data(std::vector<star_data*>& data_vector, int mode)
{
   switch (mode)
   {
   case 1:
      std::sort(data_vector.begin(), data_vector.end(), compare_name);
      break;
   case 2:
      std::sort(data_vector.begin(), data_vector.end(), compare_mass);
      break;
   case 3:
      std::sort(data_vector.begin(), data_vector.end(), compare_class_name);
      break;
   case 4:
      std::sort(data_vector.begin(), data_vector.end(), compare_parent_name);
      break;
   }
}

void delete_data(std::vector<star_data*>& data_vector)
{
   for (std::vector<star_data*>::iterator iter = data_vector.begin(); iter != data_vector.end(); iter++)
      delete *iter;
   data_vector.clear();
}

.......
//   И пример использования всего этого дела -
   std::vector<star_data*> data_vector;
   read_data("test.txt", data_vector);
   sort_data(data_vector, 1);
   write_data("test.txt", data_vector);
.......
//   Ну и конечно, удалить все при повторном чтении и при выходе -
   delete_data(data_vector);
.......

 Профиль  
                  
 
 
Сообщение19.11.2005, 02:17 
Заслуженный участник


28/10/05
1368
Я думаю незванный гость не будет против. Размещаю его советы по поводу использования strtok().

Обычно strtok() используется примерно так:

Код:
char* buffer; // исходный буфер, заполняется вне этого фрагмента программы
char* ptr;

ptr = strtok(buffer, ","); // здесь запятая - пример разделителя. заменяется на то что нужно - \n, ;
while (ptr != NULL) {
  // обрабатываем найденный фрагмент, начало строки в ptr
  ...

  ptr = strtok(NULL, ",");  // здесь опять запятая - пример разделителя.
}


Усе. Важно две вещи: 1) нельзя использовать strtok() для разбора внутри этого цикла (вместо многоточия); 2) вовремя остановиться - если кто-нибудь напихает больше полей, чем программа понимает.

Посему еще один - считающий - вариант кода:

Код:

#define MAXFIELD  3 // максимальное количество полей

char* buffer; // исходный буфер, заполняется вне этого фрагмента программы
char* ptr;
int fieldno; // номер поля


for (fieldno = 0, ptr = strtok(buffer, ","); (ptr != NULL) && (fieldno < MAXFIELD); ++fieldno, ptr = strtok(NULL, ",")) {
  // обрабатываем найденный фрагмент, начало строки в ptr, номер в fieldno
  ...

}


Все тоже самое, но цикл не пытается читать больше чем MAXFIELD полей, да и номер поля доступен.

Еще один совет - не забудьте обNULLить поля перед чтением. А то, если не все поля заданы в файле, грязь, однако, в указателях останется.

 Профиль  
                  
 
 
Сообщение19.11.2005, 02:24 
Заслуженный участник


28/10/05
1368
stars.dat

Код:
;20.000000;B0 Ia;Orion;
eta Cassiopeiae;0.000000;G3 V;Cassiopeia;
Sol;1.000000;?;?;
Epsilon Indi;0.770000;K5 Ve; Indus;
Eta Carinae;150.000000;KKK;Carina;
Alpha Aquilae;1.700000;A7 IV-V;Aquila;
proxima;34.500000;IU;tren;



stars.c

Код:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>


typedef struct star_type
{
   char*   Name;
   float   Mass;
   char*   Class;
   char*   Constellation;
   int      IsSorted;
} STAR;

typedef struct stars_list_type
{
   int      Num_stars;
   STAR**   Stars;
} STAR_LIST;



void add_star(STAR_LIST* star_list, char* name, float mass, char* class_, char* constellation)
{
   STAR* new_star;

   new_star = (STAR*)malloc(sizeof(STAR));


   new_star->Name = (char*)malloc(strlen(name) + 1);
   strcpy(new_star->Name, name);

   new_star->Mass = mass;

   new_star->Class = (char*)malloc(strlen(class_) + 1);
   strcpy(new_star->Class, class_);

   new_star->Constellation = (char*)malloc(strlen(constellation) + 1);
   strcpy(new_star->Constellation, constellation);


   if (star_list->Num_stars == 0)
      star_list->Stars = (STAR**)malloc(sizeof(STAR*));
   else
      star_list->Stars = (STAR**)realloc(star_list->Stars, (star_list->Num_stars + 1) * sizeof(STAR*));

   star_list->Stars[star_list->Num_stars] = new_star;

   star_list->Num_stars++;
}


void read_from_file(char filename[20], STAR_LIST* star_list)
{
   FILE* f;
   char line[100];
   char* name, *class_, *constellation, *ptr, *ptr1;
   float mass;

   f = fopen(filename, "r");

   while (!feof(f))
   {
      fgets(line, 100, f);

      name = line;

      ptr = strchr(line, ';');
      if (!ptr)
         continue;
      *ptr = 0;
      ptr1 = ptr + 1;

      ptr = strchr(ptr1, ';');
      if (!ptr)
         continue;
      *ptr = 0;
      mass = atof(ptr1);
      class_ = ptr + 1;

      ptr = strchr(class_, ';');
      if (!ptr)
         continue;
      *ptr = 0;
      constellation = ptr + 1;

      ptr = strchr(constellation, ';');
      if (!ptr)
         continue;
      *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 order)
{
   STAR_LIST star_list_order;
   int i, j, num;
   float big_mass;
   char* name, *constellation;

   for(i=0; i<star_list->Num_stars; i++)
      star_list->Stars[i]->IsSorted = 0;

   star_list_order.Num_stars = 0;

   for(i=0; i<star_list->Num_stars; i++)
   {
      switch (order)
      {
         case 4:
            for(j=0; j<star_list->Num_stars; j++)
            {
               if (star_list->Stars[j]->IsSorted == 0)
               {
                  big_mass = star_list->Stars[j]->Mass;
                  num = j;
               }
            }
            for(j=0; j<star_list->Num_stars; j++)
            {
               if (star_list->Stars[j]->IsSorted == 1)
                  continue;

               if (star_list->Stars[j]->Mass > big_mass)
               {
                  big_mass = star_list->Stars[j]->Mass;
                  num = j;
               }
            }
            break;

         case 5:
            for(j=0; j<star_list->Num_stars; j++)
            {
               if (star_list->Stars[j]->IsSorted == 0)
               {
                  name = star_list->Stars[j]->Name;
                  num = j;
               }
            }
            for(j=0; j<star_list->Num_stars; j++)
            {
               if (star_list->Stars[j]->IsSorted == 1)
                  continue;

               if (strcmp(star_list->Stars[j]->Name, name) < 0)
               {
                  name = star_list->Stars[j]->Name;
                  num = j;
               }
            }
            break;

         case 6:
            for(j=0; j<star_list->Num_stars; j++)
            {
               if (star_list->Stars[j]->IsSorted == 0)
               {
                  constellation = star_list->Stars[j]->Constellation;
                  num = j;
               }
            }
            for(j=0; j<star_list->Num_stars; j++)
            {
               if (star_list->Stars[j]->IsSorted == 1)
                  continue;

               if (strcmp(star_list->Stars[j]->Constellation, constellation) < 0)
               {
                  constellation = star_list->Stars[j]->Constellation;
                  num = j;
               }
            }
            break;
      }
      if (star_list_order.Num_stars == 0)
         star_list_order.Stars = (STAR**)malloc(sizeof(STAR*));
      else
         star_list_order.Stars = (STAR**)realloc(star_list_order.Stars, (star_list_order.Num_stars + 1) * sizeof(STAR*));

      star_list_order.Stars[star_list_order.Num_stars] = star_list->Stars[num];
      star_list_order.Num_stars++;
      star_list->Stars[num]->IsSorted = 1;
   }

   for(i=0; i<star_list->Num_stars; i++)
      print_star(star_list_order.Stars[i]);
}


void add_new_star(STAR_LIST* star_list)
{
   char name[30], class_[30], constellation[30];
   float mass;
   char ch;

   printf("Name of star: ");
   gets(name);
   printf("Mass of star: ");
   scanf("%f%c", &mass, &ch);
   printf("Class: ");
   gets(class_);
   printf("Constellation: ");
   gets(constellation);

   add_star(star_list, name, mass, class_, constellation);
}


void correct_star(STAR_LIST* star_list)
{
   int i, k, num, choice;
   char str[5];
   char ch;

   k = 0;
   for(i=0; i<star_list->Num_stars; i++)
   {
      printf("%d) %s ", i, star_list->Stars[i]->Name);
      k++;
      if (k == 3)
      {
         putchar('\n');
         k = 0;
      }
   }
   printf("\nWhat's the stars number you want to edit?: ");
   scanf("%d%c", &num, &ch);

   if ((num < 0) || (num > star_list->Num_stars))
      return;
   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('>');
   gets(str);
   choice = atoi(str);

   switch (choice)
   {
      case 1:
         printf("Name of star: ");
         gets(star_list->Stars[num]->Name);
         break;
      case 2:
         printf("Mass of star: ");
         scanf("%f%c", &(star_list->Stars[num]->Mass),&ch);
         break;
      case 3:
         printf("Class: ");
         gets(star_list->Stars[num]->Class);
         break;
      case 4:
         printf("Constellation: ");
         gets(star_list->Stars[num]->Constellation);
         break;
   }
}

void write_to_file(char filename[20], STAR_LIST* star_list)
{
   FILE* f;
   int i;

   f = fopen(filename, "w");

   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);
   fflush(f);
}


void main()
{
   STAR_LIST star_list;
   char filename[20];
   int order, choice;
   char str[5];
   
   order = 5;
   star_list.Num_stars = 0;

   strcpy(filename, "stars.dat");
   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('>');
      gets(str);

      if ((str[0] == 'x') || (str[0] == 'X'))
         break;

      choice = atoi(str);

      switch (choice)
      {
         case 1:
            show_contents(&star_list, order);
            break;
         case 2:
            add_new_star(&star_list);
            write_to_file(filename, &star_list);
            break;
         case 3:
            correct_star(&star_list);
            write_to_file(filename, &star_list);
            break;
         case 4:
         case 5:
         case 6:
            order = choice;
            show_contents(&star_list, order);
            break;
      }
   }

}


А теперь как любит говорить моя подруга: "А., это был не сильно бред?" Вобщем скажите, что не так.

 Профиль  
                  
 
 
Сообщение19.11.2005, 06:12 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:

- программа совершенно не защищена. Т.е., пока данные правильные, все может быть хорошо. Но не дай Бог что-то не так. Например, пользователь введет слишком длинное имя звезды. Или выберет несуществующий пункт меню. Или 'star.dat' не найден / только для чтения. Или строки в файле окажется больше 100. Или..... gets() пользоваться нельзя! если жить не надоело. Можно написать что-нибудь типа fgets(s, sizeof(s)-1, stdin) - куда надежнее (хотя конец строки все равно надо обрабатывать).

- в read/write() передается параметром char filename[20]. Один вопрос и одно предложение. Вопрос: почему 20? Предложение: строки принято передавать как char* filename. Философски, это в общем не read/write() собачье дело, какой длины filename. И непонятно, зачем строку копировать в массив. Вроде бы не обрабатывается ведь.

- после закрытия файла никкакие опреации с ним невозможны. В частности, его нельзя flush(). Да и незачем - эту работу close() должен сделать.

- с сортировкой что-то уж совсем крутое. Сразу не понять. А что, с qsort() были проблемы?

- программа не освобождает память. Это обычно дурной тон.

- я предпочитаю префиксные (++var) операции постфиксным (var++). Можете меня долго пинать :) . Этот дурной тон пошел с 70-лохматых Кернигана и Ричи. В C почти не заметно (если пользоваться правильно), но в C++ могут быть крутые наколки с объектами. У некоторых компиляторов обламывает оптимизацию (я видел такое). Так что, если по барабану - выбираем префиксный вариант.

 Профиль  
                  
 
 
Сообщение19.11.2005, 10:56 
Заслуженный участник


28/10/05
1368
незванный гость писал(а):
А что с qsort() были проблемы?


Со всем были проблемы :( В конце дошло...а-а не компилится, ну, мы щас его чуточку подправим.. :)

strtok() тоже не пошла..

Я понимаю, что это оценка профессионального программиста, но все же не думала, что будет так плохо. Хотя чего тут ждать, хорошо, что "," с ";" не путаю.

Всё же не пойму, как можно научиться :roll: программированию. Много практики? Вот, как видно, книги не помогают..

А где можно почитать о правилах хорошего тона в С? Есть где-то в рядок выписанные? :D

 Профиль  
                  
 
 
Сообщение21.11.2005, 08:44 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:

К сожалению, Вы не правильно поняли. Это была не оценка, а советы профессионала. Если честно, мне и лень, и неинтересно оценивать. Попытаться помочь, объяснить - дело другое.

Как научиться программировать - вопрос философский. Глупый ответ - из анекдота: "Как Вы печете такой вкусный хлеб? -- Очень просто. Мука, вода, немного соли, и тридцать лет у плиты.".

Я думаю, вопрос заслуживает отдельной темы. Начнете - я отвечу. Люблю, однако, провокации. А здесь дам только один совет, который вычитал в предисловии к книжке Вирта: читайте чужие программы, и пытайтесь понять их автора. Ну, и чтобы было проще следовать совету:
Код:
#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++ (//), тогда их прдется заменить на /* */. Обратите внимение на служебные функции. Их должно быть еще большею Например, ввод имени звезды встречается в двух местах, а преобразование массы из строки - в трех. Кроме того, мне не очевидно, не следует ли хранить массу в числовом и строковом виде - поскольку преобразование строка (в файле) -> число (в программе) -> строка в файле не гарантирует неизменность числа. Обратите внимание на метод захвата памяти для списка звезд - большими кусками. И еще, при редактрровании ни в коем случае нельзя читать в старые буфера. Новое имя может просто оказаться длинее, и что тогда?

И главное - не стесняйтесь задавать вопросы! :D Очень надеюсь, их будет много. И они не иссякнут после сдачи...

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 105 ]  На страницу 1, 2, 3, 4, 5 ... 7  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group