2014 dxdy logo

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

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




 
 Помогите с файлами в СИ
Сообщение10.05.2008, 10:05 
Написал программу в Си , которая должна записывать список в файл, затем читать список из файла и выводит на экран.Но программа вылетает .Помогите, пожалуйста, найти ошибку.Заранее спасибо.Вот текст программы :
if(choice==3)
appeand();
/#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#define N 3
struct student {
char name[50];
char surname[50];
unsigned char year;
struct student* next;
struct student* prev;
} ;

struct student* InputElement(){
struct student* p=(struct student*)malloc(sizeof(struct student));
printf("input name:\n");
scanf("%s",p->name);
printf("input surname:\n");
scanf("%s",p->surname);
printf("input age:\n");
scanf("%d",&(p->year));
p->next=NULL;
p->prev=NULL;
return p;
};

struct student* AddToList(struct student* root,struct student* p){
if(NULL==p){
return root;
};
p->next=root;
p->prev=p->next;
return p;
};
void Max(struct student* root){
if(NULL==root)
return;
struct student* p=root;
int max;
while(p->next!=NULL){
if (p->next->year>max) {
max=p->next->year;
}
p=p->next;
}

printf("A senior student is %d\n**********************\n",max);

};

void Output(struct student* p){
while(p!=NULL){
printf("%s\t",p->name);
printf("%s\t",p->surname);
printf("%d\n",p->year);
p=p->next;
};
};

void FreeList(struct student* root){
if(NULL==root)
return;
struct student* q=root;
struct student* p=root->next;
struct student* f=root->prev;
while (q){

if(q==NULL){
return;
}
free(q);
q=p;
if(q){
p=q->next;
f=q->prev;
};
};
};
long size(FILE*f){
long current=ftell(f);
fseek(f,0,SEEK_END);
long size=ftell(f);
fseek(f,current,SEEK_SET);
return size;
}
struct student* root=NULL;
void write(){
for(int i=0;i<N;i++){
root=AddToList(root,InputElement());
};
struct student*p=root;
FILE*f2=fopen("student.txt","w");
while(p!=NULL){
fwrite(p,sizeof(p),1,f2);
p=p->next;
};
Max(root);
Output(root);
FreeList(root);
fclose(f2);
}
void read(){
FILE*f2=fopen("student.txt","r");
struct student*p=(struct student*)malloc(sizeof(struct student));
fread(&p,sizeof(p),1,f2);
while(p!=NULL){
for(int i=0;i<N;i++){
root=AddToList(root,p);
};
p=p->next;
};
Output(root);
fclose(f2);
}
void appeand(){
FILE*f2=fopen("student.txt","a");
long offset=ftell(f2);
void*e=(FILE*)malloc(offset);
for(int i=0;i<N;i++){
root=AddToList(root,InputElement());
}
struct student*p=root;
while(p!=NULL){
fwrite(e,sizeof(p),1,f2);
p=p->next;
};
free(e);
FreeList(root);
fclose(f2);
}


void main(){
int choice;
printf("1-read\n2-write\n3-appeand\n");
scanf("%d",&choice);
if(choice==1)
read();
if(choice==2)
write();
}

 
 
 
 
Сообщение10.05.2008, 11:35 
Даже смотреть не буду, пока не вставите текст программы в тег CODE, и не отформатируете по-человечески.

Далее, "программа вылетает" - это слишком общий симптом. Конкретизируйте, как, как часто, при каком действии вылетает. Что из отладочных средств Вы пробовали применить и т.п.

 
 
 
 
Сообщение10.05.2008, 13:26 
Извините. а вы можете сказать .что такое тэг Code ? Программа вылетает. когда я хочу прочитать записанный список в файл.

 
 
 
 
Сообщение10.05.2008, 15:41 
Цитата:
Извините. а вы можете сказать .что такое тэг Code ?

В начале текста Вашей программы пишите [cоde], в конце - [/cоde], или, что тоже самое, выделяете мышкой весь текст Вашей программы в окошке браузера, и жмете на кнопочку Code сверху окошка набора сообщения. Она делает то же самое. При этом оформление текста Вашей программы сохраняется (отступы, табуляция и пр.), а также программа попадает в красиво оформленную, отделенную часть сообщения.

Цитата:
Программа вылетает. когда я хочу прочитать записанный список в файл.

Извините, не понял - так прочитать из файла, или все-таки записать в файл???

 
 
 
 
Сообщение10.05.2008, 16:36 
Код:
if(choice==3)
appeand();
/#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#define N 3
struct student {
char name[50];
char surname[50];
unsigned char year;
struct student* next;
struct student* prev;
} ;

struct student* InputElement(){
struct student* p=(struct student*)malloc(sizeof(struct student));
printf("input name:\n");
scanf("%s",p->name);
printf("input surname:\n");
scanf("%s",p->surname);
printf("input age:\n");
scanf("%d",&(p->year));
p->next=NULL;
p->prev=NULL;
return p;
};

struct student* AddToList(struct student* root,struct student* p){
if(NULL==p){
return root;
};
p->next=root;
p->prev=p->next;
return p;
};
void Max(struct student* root){
if(NULL==root)
return;
struct student* p=root;
int max;
while(p->next!=NULL){
if (p->next->year>max) {
max=p->next->year;
}
p=p->next;
}

printf("A senior student is %d\n**********************\n",max);

};

void Output(struct student* p){
while(p!=NULL){
printf("%s\t",p->name);
printf("%s\t",p->surname);
printf("%d\n",p->year);
p=p->next;
};
};

void FreeList(struct student* root){
if(NULL==root)
return;
struct student* q=root;
struct student* p=root->next;
struct student* f=root->prev;
while (q){

if(q==NULL){
return;
}
free(q);
q=p;
if(q){
p=q->next;
f=q->prev;
};
};
};
long size(FILE*f){
long current=ftell(f);
fseek(f,0,SEEK_END);
long size=ftell(f);
fseek(f,current,SEEK_SET);
return size;
}
struct student* root=NULL;
void write(){
for(int i=0;i<N;i++){
root=AddToList(root,InputElement());
};
struct student*p=root;
FILE*f2=fopen("student.txt","w");
while(p!=NULL){
fwrite(p,sizeof(p),1,f2);
p=p->next;
};
Max(root);
Output(root);
FreeList(root);
fclose(f2);
}
void read(){
FILE*f2=fopen("student.txt","r");
struct student*p=(struct student*)malloc(sizeof(struct student));
fread(&p,sizeof(p),1,f2);
while(p!=NULL){
for(int i=0;i<N;i++){
root=AddToList(root,p);
};
p=p->next;
};
Output(root);
fclose(f2);
}
void appeand(){
FILE*f2=fopen("student.txt","a");
long offset=ftell(f2);
void*e=(FILE*)malloc(offset);
for(int i=0;i<N;i++){
root=AddToList(root,InputElement());
}
struct student*p=root;
while(p!=NULL){
fwrite(e,sizeof(p),1,f2);
p=p->next;
};
free(e);
FreeList(root);
fclose(f2);
}


void main(){
int choice;
printf("1-read\n2-write\n3-appeand\n");
scanf("%d",&choice);
if(choice==1)
read();
if(choice==2)
write();
}[code][/code]



Добавлено спустя 27 секунд:

Программа вылетает при чтении из файла.

 
 
 
 
Сообщение10.05.2008, 17:24 
Товарищ! Хорошо, что Вы научились работать с тегом CODE, однако форматирования текста программы у Вас как не было, так и нет! Расставьте пробелы и/или знаки табуляции где это нужно, в соответствии со стандартами языка Си, будьте добры!

Не анализируя текст Вашей программы, фраза "Программа вылетает при чтении из файла." наводит на мысль о том, что Вы не выделили достаточно памяти, или выделили ее криво, для данных, читаемых из файла. В любом случае, после запуска Вашей программы в 90% случаев, должно выводиться сообщение, позволяющее как-то проанализировать причину "вылета". Напишите ОС и компилятор, который Вы используете!

Добавлено спустя 4 минуты 40 секунд:

Пример правильного форматирования текста программы Вы можете посмотреть, например, тут.

 
 
 
 
Сообщение10.05.2008, 18:36 
Код:
if(choice==3)
appeand();
/#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#define N 3
struct student
{
   char name[50];
   char surname[50];
   unsigned char year;
   struct student* next;
   struct student* prev;
} ;

struct student* InputElement()
{
    struct student* p=(struct student*)malloc(sizeof(struct student)); 
    printf("input name:\n");
    scanf("%s",p->name);
    printf("input surname:\n");
    scanf("%s",p->surname);
    printf("input age:\n");
    scanf("%d",&(p->year));
    p->next=NULL;
    p->prev=NULL;
    return p;
};

struct student* AddToList(struct student* root,struct student* p)
{
  if(NULL==p)
   {
     return root;
   };
  p->next=root;
  p->prev=p->next;
  return p;
};
void Max(struct student* root)
{
  if(NULL==root)
  return;
  struct student* p=root;
  int max;
  while(p->next!=NULL){
  if (p->next->year>max)
  {
     max=p->next->year;
  }
   p=p->next;
}

printf("A senior student is %d\n**********************\n",max);

};

void Output(struct student* p)
{
   while(p!=NULL)
  {
     printf("%s\t",p->name);
     printf("%s\t",p->surname);
     printf("%d\n",p->year);
     p=p->next;
   };
};

void FreeList(struct student* root)
{
   if(NULL==root)
   return;
   struct student* q=root;
   struct student* p=root->next;
   struct student* f=root->prev;
   while (q)
  {

     if(q==NULL)
    {
   return;
    }
    free(q);
    q=p;
    if(q)
      {
    p=q->next;
    f=q->prev;
      };
   };
};
long size(FILE*f)
{
   long current=ftell(f);
   fseek(f,0,SEEK_END);
   long size=ftell(f);
   fseek(f,current,SEEK_SET);
   return size;
}
struct student* root=NULL;
void write()
{
   for(int i=0;i<N;i++)
  {
     root=AddToList(root,InputElement());
  };
  struct student*p=root;
  FILE*f2=fopen("student.txt","w");
  while(p!=NULL)
   {
     fwrite(p,sizeof(p),1,f2);
     p=p->next;
   };
  Max(root);
  Output(root);
  FreeList(root);
  fclose(f2);
}
void read()
{
  FILE*f2=fopen("student.txt","r");
  struct student*p=(struct student*)malloc(sizeof(struct student));
  fread(&p,sizeof(p),1,f2);
  while(p!=NULL)
   {
    for(int i=0;i<N;i++)
     {
     root=AddToList(root,p);
     };
   p=p->next;
   };
  Output(root);
  fclose(f2);
}
  void appeand()
{
  FILE*f2=fopen("student.txt","a");
  long offset=ftell(f2);
  void*e=(FILE*)malloc(offset);
  for(int i=0;i<N;i++)
    {
     root=AddToList(root,InputElement());
    }
  struct student*p=root;
  while(p!=NULL)
    {
     fwrite(e,sizeof(p),1,f2);
     p=p->next;
     };
  free(e);
  FreeList(root);
  fclose(f2);
}


  void main()
{
  int choice;
  printf("1-read\n2-write\n3-appeand\n");
  scanf("%d",&choice);
  if(choice==1)
  read();
  if(choice==2)
  write();
}[code][/code]


Добавлено спустя 39 секунд:

Я использую Microsoft VIsual studio.

 
 
 
 
Сообщение10.05.2008, 21:47 
Несколько вопросов:

1. Какого типа ваш файл с данными? Судя по расширению - текстовый, судя по операциям чтения-записи - двоичный.
Какой тип Вы указали в Вашей программе?

2. Для переменной
Код:
struct student *p;
чему равно
Код:
sizeof(p)
?

3. Почему у Вас конец функции main() залез в начало кода? :)

 
 
 
 
Сообщение10.05.2008, 23:29 
1.Мой файл с данными должен быть текстовым .Как написать операцию чтения и записи, так что бы он оставался текстовым?
2.Честно говоря, даже не знаю. Это очень важно ?
3.Извиняюсь:)))

 
 
 
 
Сообщение11.05.2008, 01:20 
Dmytro Sheludchenko писал(а):
2.Честно говоря, даже не знаю. Это очень важно ?
Два моих вопроса (3-й не в счет) касаются принципиальных проблем Вашей программы, которые сразу бросаются в глаза. Это была подсказка для Вас:
1) Вы открываете текстовый файл, открываете в режиме "text", но читаете как двоичный.
2) Если бы файл вдруг случайно оказался двоичным, открытым в режиме "binary", то все равно Вы неправильно задаете размер записи.
sizeof(p) - это размер указателя, а не размер struct student, на которую он указывает.

Цитата:
Как написать операцию чтения и записи, так что бы он оставался текстовым?
Вам бы учебник почитать...

 
 
 
 
Сообщение11.05.2008, 10:12 
В учебнике Кернигана очень мало сказано про файлы и работу с ними В этом и проблема.Не могли бы Вы подсказать мне, как решить эту проблему?

 
 
 
 
Сообщение11.05.2008, 10:49 
Dmytro Sheludchenko писал(а):
В учебнике Кернигана очень мало сказано про файлы и работу с ними В этом и проблема.Не могли бы Вы подсказать мне, как решить эту проблему?
Книга Кернигана и Ричи - это учебник по языку С. А работа с файлами в С - это не часть языка, а часть библиотеки поддержки. Смотрите учебники по VS, Help/MSDN. Есть примеры, поставляемые вместе с VS.

 
 
 
 
Сообщение12.05.2008, 05:05 
Первый корень ваших проблем -- непонимание разницы между
char abc[50];
и
char *abc;

В первом случае распределяется 50 байт под массив. Вы можете сразу сделать scanf("%s", abc); и пользователь может ввести не более 50 байт, иначе -- выход за границы памяти (ошибку не получите, но времени на отладку потратите прилично).

Во втором случае в памяти распределяется указатель. Только указатель, указывающий на случайную ячейку памяти. Перед его использованием сначала нужно выделить память и записать полученный указатель в abc. Только после этого возможно scanf("%s", abc); Снова, если пользователь введёт больше данных, чем выделено памяти -- выход за границы памяти.

Разница в том, что в первом случае у вас массив char[50], точно так же как и был бы int[123], и double[456]. Просто в Си значением переменной-массива является адрес её нулевого элемента, то есть, указатель на нулевой элемент,

Во втором случае -- просто указатель.

Другая проблема исходит из первой. sizeof(имя переменной) равняется sizeof(тип этой переменной). Пусть у вас
struct student st;
В данном случае st -- это сама структура. Под неё уже выделена память. sizeof(p) или sizeof(struct student) будет включать размер всей структуры, всех её полей.

Второй вариант:
struct student *p;
Тут p -- просто указатель. Без разницы, какой адрес памяти вы ему присвоите, размер самого указателя не изменится. Так вот, sizeof(p) или sizeof(struct student *) это и есть размер самого указателя. Это размер той памяти, которая достаточна для хранения адреса структуры struct student.

Общие замечания по коду:
* не ставьте точки с запятой после блоков функций, после блоков while(){}, if(){} и так далее. В Си точка с запятой после блока с кодом никогда не ставится (в смысле, не требуется синтаксически, как в паскале function ... begin ... end; <-- тут нужна точка с запятой). Да, это разрешено синтаксисом, и даже работает, но обозначает совершенно не то, что вы ожидали (в Си точка с запятой сама по себе обозначает "пустой оператор" -- указание "ничего не делать").

* пользуйтесь отступами. Вам может показаться, что это лишняя трата времени, но подумайте о следующем. Расстановка отступов займёт от силы минуты три. А ваш код форумчане рассматривают уже два дня. Да я мне кажется, что и вы сами как минимум пол-часа просто смотрели на свой код, пытаясь найти ошибки. Расстановка отсупов и пробелов внутри выражений здорово помогает чтению кода.

 
 
 [ Сообщений: 13 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group