1

Тема: обмін даними в файлах

Ось повне завдання:
Запишіть в файл nf чисел типу float, прочитайте число з позицій nf-3. Після цього допишіть в файл ncданних типу char, прочитайте цей з nc / 4 позиції. Допишите в файл ni чисел типу int. Прочитайте число з позиції ni-3. Для перевірки лічені дані вивести на екран. Роздрукуйте вміст файлу - всі введені дані повинні бути присутніми в файлі. У процесі введення-виведення даних використовуйте функції роботи з файлом fopen, fseek, ftell, rewind, fgetpos, fsetpos, fclose.
Ось код:

#include<stdio.h>
#include<conio.h>
void main() {
  int nf, nc, ni;
  int mf[20], fn;
  char mc[20], cn;
  float mi[20], in;
  FILE *fp;
  fp = fopen("files.txt", "w+");
  if (fp == NULL) {
    printf("file can not be opened: error \n");
    return;
  }
  fflush(stdin);
  rewind(fp);
  printf("\tinput: nf - number of float :\nnf= ");
  scanf("%f", &nf);
  printf("Enter float data\n");
  for (int i=0; i < nf; i++) {
    mf[i] = getche();
  }
  puts(" ");
  for (int i=0; i < nf; i++) {
    printf("%f ", mf[i]);
    fprintf(fp, "%f", mf[i]);
  }
  fseek(fp, (nf-3), SEEK_SET);
  fscanf(fp, "%f", &fn);
  printf("\nRead off float: %f\n", fn);
  rewind(fp);
  fseek(fp, nf, SEEK_SET);
  printf("\tinput: nc - number of char:\nnc= ");
  scanf("%c", &nc);
 
  printf("Enter char data\n");
  for (int i=0; i < nc; i++) {
    scanf("%c", &mc[i]);
  }
  for (int i=0; i < nc; i++) {
    printf("%c ", mc[i]);
    fprintf(fp, "%c ", mc[i]);
  }
  if ((nc %4)) { fseek(fp, nf*3 * (nc / 4), SEEK_SET); }
   else fseek(fp, nf*3 * (nc / 4) - 1, SEEK_SET);
  fscanf(fp, "%c", &cn);
  printf("\nRead off char: %c\n", cn);
  rewind(fp);
  p:printf("\tinput: ni - number of int :\n!!!ni>3!!!\nni= ");
  scanf("%d", &ni);
  if (ni <= 3) { printf("\nError.Try again\n"); goto p; }
 
  printf("Enter int data\n");
  for (int i = 0; i < ni; i++) {
    scanf("%d", &mi[i]);
  }
  rewind(fp);
  fseek(fp, 3+ nc + nf, SEEK_SET);
  for (int i = 0; i < ni; i++) {
    printf("%d ", mi[i]);
    fprintf(fp, "%d", mi[i]);
  }
  fseek(fp, 8 * (ni -4) + nf + 3 + nc, SEEK_SET);
  fscanf(fp, "%d", &in);
  printf("\nRead off int: %d\n", in);
  printf("All read off elements: %df, %c, %d", fn, cn, in);
  fclose(fp);
  _getch();
}

не можу зрозуміти де помилки, але виводить не зовсім те що треба
Допоможіть, будь ласка,  їх знайти і підкажіть як їх виправити

2 Востаннє редагувалося koala (08.11.2018 21:31:57)

Re: обмін даними в файлах

У вас не вийде нормально переміщуватися по текстовому файлу за допомогою fseek. Тобто переміщуватися вийде, але встановити, де саме ви знаходитеся, буде дуже важко. Вам треба писати і читати за допомогою fwrite/fread.
Якщо коротко:

int x = 300;
fprintf(fp,"%d",x);//у файлі байти '3','0','0', або  16-річними кодами  0x33, 0x30, 0x30
fwrite(&x, sizeof(int), 1, fp);//у файлі байти 0x2c, 0x01, 0x00, 0x00

У першому випадку кількість байтів на одне число виходить різним - 1 буде займати 1 байт, 300 - три, а 1000000 - цілих 7; якщо вказівник файла вказує на початок одного числа, а нам треба зміститися на наступне, то ми не зможемо цього зробити, не прочитавши це число - звідки ми знатимемо, що число вже закінчилося?
У другому число типу int буде займати завжди однаковий розмір - sizeof(int) (у сучасних компіляторах це зазвичай 4 байти); завдяки цьому fseek може точно виставити позицію потрібного int-а (чи float-а). Так, char з позиції nc/4 після nf float-ів буде знаходитися за адресою nf*sizeof(float)+(nc/4)*sizeof(char):

char c;
fseek(fp,nf*sizeof(float)+(nc/4)*sizeof(char), SEEK_SET);
fread(&c,sizeof(char),1,fp);//прочитає потрібний символ

Крім того, fwrite може писати за одну операцію одразу цілий масив (кількість елементів - третій параметр); а fread, відповідно, читати.

3

Re: обмін даними в файлах

не могли б підказати, чому ось так код працює
умова:Запишіть у файл   даних типу  , прочитайте дане з позиції  . Після цього допишіть у файл   чисел типу  . Прочитайте число з позиції  . Допишіть у файл   чисел типу  , прочитайте число з позицій  . Для перевірки зчитані дані вивести на екран. Роздрукуйте вмістиме файлу – всі введені дані повинні бути присутні у файлі. У процесі вводу-виводу даних використовуйте функції роботи з файлом fopen, fseek, ftell, rewind, fgetpos, fsetpos, fclose.
код:

#include<stdio.h>
#include<conio.h>

void main() {
  int nc, ni, nf, ir, ioz;
  int mi[20], in;
  char mc[20], cn;
  float mf[20], fn;
  FILE *fp;
  fp = fopen("files.txt", "w+");
  if (fp == NULL) {
    printf("file can not be opened: error \n"); return;
  }
  fflush(stdin);
  rewind(fp);
  printf("\tinput: nc - number of char :\nnc= ");
  scanf("%d", &nc);
  printf("Enter char data\n");
  for (int i=0; i < nc; i++) {
    mc[i] = getche();
  }
  puts(" ");
  for (int i=0; i < nc; i++) {
    printf("%c ", mc[i]);
    fprintf(fp, "%c", mc[i]);
  }

  fseek(fp, (nc / 2), SEEK_SET);
  fscanf(fp, "%c", &cn);
  printf("\nRead off char: %c\n", cn);
  rewind(fp);
  fseek(fp, nc, SEEK_SET);
  printf("\tinput: ni - number of int\nni= ");
  scanf("%d", &ni);

  printf("Enter int data\n");
  for (int i=0; i < ni; i++) {
    scanf("%d", &mi[i]);
  }
  for (int i=0; i < ni; i++) {
    printf("%d ", mi[i]);
    fprintf(fp, "%d ", mi[i]);
  }
  if ((ni %4)) { fseek(fp,nc+ 2 * (ni / 4), SEEK_SET); }
   else fseek(fp, nc+2 * (ni / 4) - 1, SEEK_SET);
  fscanf(fp, "%d", &in);
  printf("\nRead off int: %d\n", in);
  rewind(fp);
  p:printf("\tinput: nf - number of fnt :\n!!!nf>3!!!\nnf= ");
  scanf("%d", &nf);
  if (nf <= 3) { printf("\nError.Try again\n"); goto p; }

  printf("Enter float data\n");
  for (int i = 0; i < nf; i++) {
    scanf("%f", &mf[i]);
  }
  rewind(fp);
  fseek(fp, 2 * ni + nc, SEEK_SET);
  for (int i = 0; i < nf; i++) {
    printf("%f ", mf[i]);
    fprintf(fp, "%f", mf[i]);
  }
  fseek(fp, 8 * (nf -4) + nc + 2 * ni, SEEK_SET);
  fscanf(fp, "%f", &fn);
  printf("\nRead off float: %f\n", fn);
  printf("All read off elements: %d, %c, %f", in, cn, fn);
  fclose(fp);
  _getch();
}


а якщо переробляти під мою умову, то не працює як слід?

koala написав:

У вас не вийде нормально переміщуватися по текстовому файлу за допомогою fseek. Тобто переміщуватися вийде, але встановити, де саме ви знаходитеся, буде дуже важко. Вам треба писати і читати за допомогою fwrite/fread.
Якщо коротко:

int x = 300;
fprintf(fp,"%d",x);//у файлі байти '3','0','0', або  16-річними кодами  0x33, 0x30, 0x30
fwrite(&x, sizeof(int), 1, fp);//у файлі байти 0x2c, 0x01, 0x00, 0x00

У першому випадку кількість байтів на одне число виходить різним - 1 буде займати 1 байт, 300 - три, а 1000000 - цілих 7; якщо вказівник файла вказує на початок одного числа, а нам треба зміститися на наступне, то ми не зможемо цього зробити, не прочитавши це число - звідки ми знатимемо, що число вже закінчилося?
У другому число типу int буде займати завжди однаковий розмір - sizeof(int) (у сучасних компіляторах це зазвичай 4 байти); завдяки цьому fseek може точно виставити позицію потрібного int-а.
Крім того, fwrite може писати за одну операцію одразу цілий масив (кількість елементів - третій параметр).

4

Re: обмін даними в файлах

Умова трохи побилася; але у мене цей код працює неправильно - зокрема, якщо ввести 4 цілих числа 1001, 1002, 1003 і 1004, він жодного з них не читає.
Чому - я вже вам відповів: ви не можете пересуватися по елементах, розмір яких невідомий, не розбираючи ці елементи. Тут трохи пощастило із завданням: першими йдуть char-и, вони якраз мають фіксований розмір в 1 байт, а з float-ів треба прочитати, як я розумію, перший, тобто скільки займають інші float-и, не має значення. Значення має кількість байт на int - автор програми вважав, що їх потрібно 2 (оскільки він виводить пробіли, то розраховував виключно на однозначні).

5 Востаннє редагувалося koala (09.11.2018 12:30:24)

Re: обмін даними в файлах

А ще у вас масив int-ів зветься nf, і ви його використовуєте, як float. І є goto та два оператори в одному рядку.
Ну і взагалі ви механічно позмінювали у чужому коді всі типи на ті, про які йде мова - а так дурня вийшла. Кількість елементів у масиві - завжди ціле число,  а не char чи float.