2014 dxdy logo

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

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




 
 Си: Считывание данных с файла
Сообщение06.05.2014, 17:50 
Дана вот такая задача:

Во входном файле заданы 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 
Вы перевод строки не пропускаете, вот и.

 
 
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 16:20 
Их функция fscanf сама пропускает, как и пробелы.

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

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

 
 
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 19:36 
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 
Ну и чего вы добились? Программа компилируется и при работе не ругается, а то что результат неправильный - неважно.
inky в сообщении #860239 писал(а):
Мне так и не удалось исправить этот код
Достаточно было в исходном коде убрать лишний fscanf(). Главное, вы, похоже, так и не поняли, что делает fscanf() и пишете программу наугад.

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

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

 
 
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 20:24 

(Оффтоп)

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

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

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

(Оффтоп)

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

 
 
 
 Re: Си: Считывание данных с файла
Сообщение07.05.2014, 21:37 
Я знаю что делает 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 
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 
Ну я тоже о коде из первого своего сообщения где было написано 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 
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 
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 ] 


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