2014 dxdy logo

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

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




Начать новую тему Ответить на тему
 
 Си: Считывание данных с файла
Сообщение06.05.2014, 17:50 


04/05/13
125
Дана вот такая задача:

Во входном файле заданы 2 автомата. Построить автомат, являющийся их суперпозицией: a1,…an->A->b1,…,bn->B->c1,…,cn. Для кодирования состояний результирующего автомата использовать сначала переменные, кодирующие состояния автомата A, потом переменные, кодирующие состояния автомата B.

Формат входных данных такой:

Во всех задачах про автоматы входной и выходной алфавиты всегда {0,1}, число состояний – степень двойки 2n. Автомат задается каноническими уравнениями: в 1-й строке записано n – число переменных, кодирующих состояние, потом пробел, потом значения этих переменных в начальном состоянии (без пробела) потом n строк – вектора значений (см. п.1) функций перехода (каждая от n+1 переменной, вход – последняя переменная), потом еще одна строка – вектор значений функции выхода (тоже от n+1 переменной, вход – последняя переменная). Например, единичная задержка (автомат с одним входом, одним выходом и двумя состояниями, функция перехода F(q,x)=x, функция выхода G(q,x)=q) с начальным состоянием 0 задается так:
1 0
2 2 0101
2 2 0011
При необходимости вывести состояние выводится его код, как в случае начального состояния.


Пункт первый о котором говорится в формате входных данных:

Функции алгебры логики задаются вектором значений: сначала идет число 2, означающее 2-значную логику, потом n – количество переменных функции, потом пробел, потом без пробела 2n символов – значения функции на наборах 0..00, 0..01, 0..10 и т.д.. Например, функция x+y задается строкой 2 2 0110

Для хранения автоматов я использую вот такую вот структуру:
Код:
typedef struct _task_02_3_03_auto
{
int *v;
}
AUTO;

Вот как я считываю данные:
Код:
AUTO *A, *B, *C;
int i, j, ij, n, nn, m, rn, k;
char ch;
FILE *f, *ff;
//===================================================================================
f=fopen(inFile, "rt");
if(f==NULL){return -1;}
ff=fopen(outFile, "wt");
//===================================================================================
//===========================Задаем первый автомат=================================== АВТОМАТЫ НЕПРАВИЛЬНО СЧИТЫВАЮТСЯ
fscanf(f, "%d", &n);
A=(AUTO*)malloc((n+2)*sizeof(AUTO));
A[0].v=(int*)malloc((n+1)*sizeof(int));
A[0].v[0]=n;
fscanf(f,"%c", &ch);
for(i=1;i<=n;i++)
{
  fscanf(f,"%c", &ch);
  A[0].v[i]=ch-'0';
}
//===================================================================================
for(i=1;i<=n;i++)
{
  fscanf(f, "%d", &m);
  fscanf(f, "%d", &m);
  A[i].v=(int*)malloc(((1 << (m+1))+1)*sizeof(int));
  A[i].v[0]=m;
  fscanf(f,"%c", &ch);
  for(j=1;j<=(1 << (m+1));j++)
  {
   fscanf(f,"%c", &ch);
   A[i].v[j]=ch-'0';
  }
}
//===================================================================================
fscanf(f, "%d", &m);
fscanf(f, "%d", &m);
A[n+1].v=(int*)malloc(((1 << (m+1))+1)*sizeof(int));
A[n+1].v[0]=m;
fscanf(f,"%c", &ch);
for(i=1;i<=(1 << (m+1));i++)
{
  fscanf(f,"%c", &ch);
  A[n+1].v[i]=ch-'0';
}


Не могу понять где тут закралась ошибка, почему то считывается все не так как я задумывал. Возможно я не так понимаю посимвольное считывание?
Например, пусть во входном файле задано следующее:
2
3 00101011
3 11000111
чтобы считать это в структуру которую я описывал выше, я бы использовал такой код:
Код:
AUTO *A;
FILE *f;
int i, j, n, m;
char ch;

f=fopen(infile, "rt");
fscanf(f, "%d", &n);
A=(AUTO*)malloc(n*sizeof(AUTO));
for(i=0;i<n;i++)
{
fscanf(f, "%d", &m);
A[i].v=(int*)malloc(((1 << m)+1)*sizeof(int));
A[i].v[0]=m;
fscanf(f, "%c", &ch);
for(j=1;j<=(1 << m);j++)
{
fscanf(f, "%c", &ch);
A[i].v[j]=ch-'0';
}
}

Собственно вопрос: в чем ошибка в считывании автоматов?

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 09:03 
Заслуженный участник


09/09/10
3729
Вы перевод строки не пропускаете, вот и.

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 16:20 
Заслуженный участник


04/05/09
4589
Их функция fscanf сама пропускает, как и пробелы.

-- Ср май 07, 2014 09:22:55 --

Соответственно, первый вызов
Код:
fscanf(f, "%c", &ch);
пропустит пробел и прочитает первую цифру, которую должен прочитать последующий цикл.

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 19:36 


04/05/13
125
venco в сообщении #860187 писал(а):
Их функция fscanf сама пропускает, как и пробелы.

-- Ср май 07, 2014 09:22:55 --

Соответственно, первый вызов
Код:
fscanf(f, "%c", &ch);
пропустит пробел и прочитает первую цифру, которую должен прочитать последующий цикл.

Вот и я так думаю. Мне так и не удалось исправить этот код, но мне подсказали более надежный способ. Можно сделать вот так:
Код:
char *ch;
ch=(char*)malloc((тут два в степени количество переменных)*sizeof(char));

Дальше, когда настанет пора считывать длинный ряд из нулей и еденичек, делаем так:
Код:
fscanf(f, "%c", ch);
for(i=1;i<=(тут два в степени количество переменных);i++) //в нулевом столбце записано число переменных, поэтому записываю с первого столбца
{
  A[нужная строка].v[i]=ch[i-1]-'0';
}


-- 07.05.2014, 21:39 --

(Оффтоп)

Мне повезло, попалась относительно легкая задача из автоматов. Осталось только придумать и реализовать суперпозицию функций перехода, остальное уже готово :mrgreen:

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 19:59 
Заслуженный участник


04/05/09
4589
Ну и чего вы добились? Программа компилируется и при работе не ругается, а то что результат неправильный - неважно.
inky в сообщении #860239 писал(а):
Мне так и не удалось исправить этот код
Достаточно было в исходном коде убрать лишний fscanf(). Главное, вы, похоже, так и не поняли, что делает fscanf() и пишете программу наугад.

-- Ср май 07, 2014 13:01:27 --

Совет: после кода ввода добавьте отладочный вывод - чтобы видеть, что программа правильно прочитала данные.

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 20:24 
Заслуженный участник


09/09/10
3729

(Оффтоп)

venco в сообщении #860187 писал(а):
Их функция fscanf сама пропускает, как и пробелы.

Хм, действительно. А у какой тогда сишной функции были проблемы с разрывами строк? Или я с Read из паскаля путаю?

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 21:34 
Заслуженный участник


02/08/11
7013

(Оффтоп)

Joker_vD в сообщении #860262 писал(а):
А у какой тогда сишной функции были проблемы с разрывами строк?
У gets().

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 21:37 


04/05/13
125
Я знаю что делает fscanf и пользовался посимвольным чтением в других задачах, там у меня все хорошо работало. Просто код этой задачи я написал за три часа с нуля, так как спешил и наделал там ошибок. А после подсказки однокурсника о том, что удобнее считывать вектор значений в массив строк, я решил не терять время на исправление и написал новый код который отлично работает.
После того как я исправил код который отвечает за считывание автоматов, я добился того что мой код работает правильно везде, кроме 25-30 строк отвечающих за формирование функций перехода у автомата С.
Начал уже исправлять алгоритм и похоже я знаю как это сделать.
venco в сообщении #860250 писал(а):
Совет: после кода ввода добавьте отладочный вывод - чтобы видеть, что программа правильно прочитала данные.

спасибо, но я всегда так делаю и именно так узнал об ошибке.

-- 07.05.2014, 23:40 --

venco в сообщении #860250 писал(а):
Достаточно было в исходном коде убрать лишний fscanf().

Может я не о том fscanf подумал, но мне кажется тогда программа начнет считывать вектор значений начиная с пробела (используя посимвольное чтение в других задачах я убедился, что пробелы тоже считываются если их намеренно не пропускать).
Можете конкретно указать где?

-- 07.05.2014, 23:52 --

Я понял что в исходном коде было не так: цикл слишком долгий. Он должен был продолжаться до $2^m$, а не $2^{m+1}$ :mrgreen:
У меня мозги перегрелись от такой работы тогда...я наверное подумал о том, что $m=n+1$ (это из условия задачи), и написал $m+1$ вместо $n+1$ или просто $m$ :oops:

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 22:58 
Заслуженный участник


04/05/09
4589
inky в сообщении #860285 писал(а):
Может я не о том fscanf подумал, но мне кажется тогда программа начнет считывать вектор значений начиная с пробела (используя посимвольное чтение в других задачах я убедился, что пробелы тоже считываются если их намеренно не пропускать).
Можете конкретно указать где?
fscanf не читает пробелы, а пропускает их. Поэтому
Код:
fscanf(f, "%c", &ch);
перед циклом по j прочитает первую цифру, в результате циклу цифр не хватит.
inky в сообщении #860285 писал(а):
Я понял что в исходном коде было не так: цикл слишком долгий. Он должен был продолжаться до $2^m$, а не $2^{m+1}$ :mrgreen:
В изначальном коде цикл у вас до $2^m$.

Я здесь говорю про код, который в первом сообщении. Последний исправленный вообще читает только первую цифру, а в остальные значения массива попадает мусор. Но код не зависает на вводе, это да.

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 23:23 


04/05/13
125
Ну я тоже о коде из первого своего сообщения где было написано for(j=1;j<=(1 << (m+1));j++), тогда как должно было быть for(j=1;j<=(1 << m);j++)

-- 08.05.2014, 01:25 --

venco в сообщении #860350 писал(а):
fscanf не читает пробелы, а пропускает их.

у меня он читает пробелы, так как я считываю по формату %c (в коде из первого сообщения). Я это уже проверял в других задачах как и писал выше. Если считывать по формату %s или %d например, то пробелы пропускаются автоматически.

-- 08.05.2014, 01:34 --

У меня к вам другой вопрос: не могли бы вы мне помочь с функциями переходов второго автомата? Для первого я сделал, работает все правильно, а для второго что то не получется. Вот мой код: (привожу полностью, нужную область выделил)
Код:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int task_02_3_03(const char* inFile, const char* outFile);
//===================================================================================
//===================Структура для хранения автомата=================================
typedef struct _task_02_3_03_auto
{
int *v;
}
AUTO;
//===================================================================================
//===================================================================================
int task_02_3_03(const char* inFile, const char* outFile)
{
AUTO *A, *B, *C;
int i, j, ij, ii, n, nn, m, rn, k, qt, xt, l;
char *ch, *chh;
FILE *f, *ff;
//===================================================================================
f=fopen(inFile, "rt");
if(f==NULL){return -1;}
ff=fopen(outFile, "wt");
//===================================================================================
//===========================Задаем первый автомат===================================
fscanf(f, "%d", &n);
A=(AUTO*)malloc((n+2)*sizeof(AUTO));
A[0].v=(int*)malloc((n+1)*sizeof(int));
A[0].v[0]=n;
ch=(char*)malloc((1 << (n+1))*sizeof(char));
fscanf(f, "%s", ch);
for(i=1;i<=n;i++)
{
  A[0].v[i]=ch[i-1]-'0';
}
//===================================================================================
for(i=1;i<=n+1;i++)
{
  fscanf(f, "%d", &m);
  fscanf(f, "%d", &m);
  A[i].v=(int*)malloc((1 << m)*sizeof(int));
  A[i].v[0]=m;
  fscanf(f, "%s", ch);
  for(j=1;j<=(1 << m);j++)
  {
   A[i].v[j]=ch[j-1]-'0';
  }
}
//===================================================================================
//===========================Задаем второй автомат===================================
fscanf(f, "%d", &nn);
B=(AUTO*)malloc((nn+2)*sizeof(AUTO));
B[0].v=(int*)malloc((nn+1)*sizeof(int));
B[0].v[0]=nn;
chh=(char*)malloc((1 << (nn+1))*sizeof(char));
fscanf(f, "%s", chh);
for(i=1;i<=nn;i++)
{
  B[0].v[i]=chh[i-1]-'0';
}
//===================================================================================
for(i=1;i<=nn+1;i++)
{
  fscanf(f, "%d", &m);
  fscanf(f, "%d", &m);
  B[i].v=(int*)malloc((1 << m)*sizeof(int));
  B[i].v[0]=m;
  fscanf(f, "%s", chh);
  for(j=1;j<=(1 << m);j++)
  {
   B[i].v[j]=chh[j-1]-'0';
  }
}
/*
printf("%d ", B[0].v[0]);
for(i=1;i<=nn;i++)
  printf("%d", B[0].v[i]);
printf("\n");
for(i=1;i<=nn+1;i++)
{
  printf("2 ");
  printf("%d ", B[i].v[0]);
  for(j=1;j<=(1 << (nn+1));j++)
  {
   printf("%d", B[i].v[j]);
  }
  if(i<nn+1)printf("\n");
}
getchar();getchar();
*/
//====================================================================================
//===========================Строим суперпозицию автоматов============================
rn=n+nn;
C=(AUTO*)malloc((rn+2)*sizeof(AUTO));
C[0].v=(int*)malloc((rn+1)*sizeof(int));
C[0].v[0]=rn;
for(i=1;i<=n;i++)
  C[0].v[i]=A[0].v[i];
for(i=n+1;i<=rn;i++)
  C[0].v[i]=B[0].v[i-n];
//===================================================================================
for(i=1;i<=rn+1;i++)
{
  C[i].v=(int*)malloc((1 << (rn+1))*sizeof(int));
  C[i].v[0]=rn+1;
}
//=====================Задаем функцию значений автомата С============================
k=1;
for(i=1;i<=(1 << (n+1));i+=2)
{
  for(j=1;j<=(1 << (nn+1));j+=2)
  {
   C[rn+1].v[k]=B[nn+1].v[j+A[n+1].v[i]];
   C[rn+1].v[k+1]=B[nn+1].v[j+A[n+1].v[i+1]];
   k+=2;
  }
}
/*
for(i=1;i<=(1<<(rn+1));i++)
  printf("%d", C[rn+1].v[i]);
getchar();getchar();
*/
//====================Задаем функции переходов автомата С============================
for(ij=1;ij<=n;ij++)
{
  for(j=1;j<=(1 << (rn+1));j++)
  {
   xt=(j-1)&1;
   qt=(j-1)&(1 << (rn-ij+1));if(qt!=0)qt=1;
   l=qt*(1 << (n-ij+1))+xt;
   C[ij].v[j]=A[ij].v[l+1];
  }
}
// до этого места все работает правильно
  for(ij=n+1;ij<=rn;ij++)
{
  for(j=1;j<=(1 << (rn+1));j++)
  {
   xt=(j-1)&1;l=0;
   for(ii=1;ii<=n;ii++)
   {
    qt=(j-1)&(1 << (rn-ij+1));if(qt!=0)qt=1;
    l+=qt*(1 << (n-ij+1));
   }
   l+=xt;
   xt=A[n+1].v[l+1];
   qt=(j-1)&(1 << (rn-ij+1));if(qt!=0)qt=1;
   l=qt*(1 << (nn-ij+1+n))+xt;
   C[ij].v[j]=B[ij-n].v[l+1];
  }
}/////после этого места тоже все правильно работает
//===================================================================================
//=================================Вывод автомата С==================================
fprintf(ff, "%d ", C[0].v[0]);
for(i=1;i<=rn;i++)
  fprintf(ff, "%d", C[0].v[i]);
fprintf(ff, "\n");
for(i=1;i<=rn+1;i++)
{
  fprintf(ff, "2 ");
  fprintf(ff, "%d ", C[i].v[0]);
  for(j=1;j<=(1 << (rn+1));j++)
  {
   fprintf(ff, "%d", C[i].v[j]);
  }
  if(i<rn+1)fprintf(ff, "\n");
}
//===================================================================================
fclose(f); fclose(ff);
return 0;
}


-- 08.05.2014, 01:36 --

На вот таких входных данных

1 0
2 2 0101
2 2 0011
1 0
2 2 1010
2 2 0110

выдает

2 00
2 3 01010101
2 3 11101110
2 3 00111100

тогда как правильно было бы

2 00
2 3 01010101
2 3 11110000
2 3 00111100

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 23:43 
Заслуженный участник


04/05/09
4589
inky в сообщении #860369 писал(а):
Ну я тоже о коде из первого своего сообщения где было написано for(j=1;j<=(1 << (m+1));j++), тогда как должно было быть for(j=1;j<=(1 << m);j++)
Я тоже про первое сообщение, но про второй код (только ввод). Там у вас правильный размер.

inky в сообщении #860369 писал(а):
venco в сообщении #860350 писал(а):
fscanf не читает пробелы, а пропускает их.

у меня он читает пробелы, так как я считываю по формату %c
fscanf() пропускает пробелы даже по формату %c.

inky в сообщении #860369 писал(а):
У меня к вам другой вопрос: не могли бы вы мне помочь с функциями переходов второго автомата?
Если будет время...

 Профиль  
                  
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 23:46 


04/05/13
125
venco в сообщении #860382 писал(а):
fscanf() пропускает пробелы даже по формату %c.

у меня он вроде читал, но попозже я перепроверю.

venco в сообщении #860382 писал(а):
Если будет время...

Спасибо! Если все таки додумаюсь сам как сделать, то напишу.

-- 08.05.2014, 01:57 --

Очень уж быстро я нашел ошибку в коде))
то место что я выделил в полном коде своей программы:
Код:
for(ij=n+1;ij<=rn;ij++)
{
  for(j=1;j<=(1 << (rn+1));j++)
  {
   xt=(j-1)&1;l=0;
   for(ii=1;ii<=n;ii++)
   {
    qt=(j-1)&(1 << (rn-ii+1));if(qt!=0)qt=1;//////тут и строкой ниже я заменил ij на ii и все заработало правильно))
    l+=qt*(1 << (n-ii+1));
   }
   l+=xt;
   xt=A[n+1].v[l+1];
   qt=(j-1)&(1 << (rn-ij+1));if(qt!=0)qt=1;
   l=qt*(1 << (nn-ij+1+n))+xt;
   C[ij].v[j]=B[ij-n].v[l+1];
  }
}


-- 08.05.2014, 01:58 --

(Оффтоп)

теперь я точно получу пятерку за этот симестр :mrgreen:

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 12 ] 

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



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

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


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

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