1

Тема: Використанням файлів та потоків

Завдання
Розробити програми на мові С для обробки зовнішніх файлів:
1)організувати створення двох зовнішніх файлів:      //це завдання я виконав
-  у перший текстовий файл записати розмірність матриці та значення елементів матриці;
-  у другий текстовий файл записати не менше 5-ти символьних рядків;
2)зчитати матрицю з першого текстового файлу та обчислити і вивести добуток додатних елементів масиву а44[n][m]
//а з цим виникли труднощі, оскільки я не розумію як присвоїти розмірність матриці змінним n та m, і занести саму матрицю в a44[n][m]

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int p1(void);
int p2(void);
int r1();

int main()
{
    srand(time(0));
    int p;

    do
    {
        printf("Main menu\n");
        printf("1. Create and write the first text file\n");
        printf("2. Create and write the second text file\n");
         printf("3. Process the first text file\n");
        printf("0. Exit\n");
        printf("Input number: ");
        scanf("%d", &p);
        switch(p)
        {
        case 1:
            p1();
            break;
        case 2:
            p2();
            break;
        case 3:
            r1();
    }
    } while (p!=0);
    return 0;
}

int p1(void)
{
    FILE *f1=NULL;
    int n, m;
    char name1[20];
    int matrix_row, matrix_col;
    printf("Input file's name 1: ");
    scanf("%s", name1);
    f1 = fopen(name1, "w+");
    if (f1 == NULL)
    {
        printf("Error opening file 1");
        exit(1);
    }
    printf("Input dimension matrix n and m: ");
    scanf("%d %d", &matrix_row, &matrix_col);
    printf("n = %d, m = %d\n", matrix_row, matrix_col);
    fprintf(f1, "%d\n", matrix_row);
    fprintf(f1, "%d\n", matrix_col);
    for (n=0; n<matrix_row; n++)
    {
        for (m=0; m<(matrix_col); m++)
        {
            int tmp = rand() % 21-10;
            printf("%7d", tmp);
            fprintf(f1, "%7d", tmp);
        }
        printf("\n");
        fprintf(f1, "\n");
    }
    printf("File created %s\n", name1);
    printf("\n");
    fclose(f1);
    return 0;
}

int p2(void)
{
    FILE *f2=NULL;
    char name2[20];
    char c[78];

    printf("Input file's name 2: ");
    scanf("%s", name2);
    f2 = fopen(name2, "w+");
    if (f2 == NULL)
    {
        printf("Error opening file 2");
        exit(2);
    }
    printf("Enter a blank line to stop\n");
    getchar();
    while (1)
    {
        gets(c);
        if (strlen(c)==0)
            break;
        fputs(c, f2);
        fputs("\n", f2);
    }

    fclose(f2);
    printf("File created %s\n", name2);
    printf("\n");
    return 0;
}

int r1()
{
    FILE *f1=NULL;
    int n, m;
    char a44[n][m];
    char name1[20];
    printf("Input file's name 1: ");
    scanf("%s", name1);
    f1 = fopen(name1, "r");
    if (f1 == NULL)
    {
        printf("Error opening file 1");
        exit(1);
    }
}

2

Re: Використанням файлів та потоків

Вам пощастило, що сучасний C підтримує масиви змінної довжини (VLA). Спершу читайте n і m з файлу, а потім проголошуйте 

int a[n][m]

Тільки, звісно, не char - у вас же числа, не символи, правильно? А інакше довелося б проголошувати a вказівником на int і malloc-ом виділяти пам'ять (до речі, почитайте про це і спробуйте зробити, у пригоді стане).
І пробіли розставляйте в файлі, бо fprintf(f1, "%7d", tmp) не лишає роздільників між числами.

3

Re: Використанням файлів та потоків

koala написав:

Спершу читайте n і m з файлу, а потім проголошуйте...

І пробіли розставляйте в файлі, бо fprintf(f1, "%7d", tmp) не лишає роздільників між числами.

Я тільки починаю вивчати C, тому не розумію як зчитати n і m з файлу, а потім проголосити. Для того щоб розтавити пробіли в файлі потрібно в fprintf(f1, "%7d", tmp) перед %7d поставити пробіл?

4

Re: Використанням файлів та потоків

Так само, як і писали:

FILE *file = fopen(...);
int matrix_row, matrix_col;
fscanf(file, "%d", &matrix_row);
fscanf(file, "%d", &matrix_col);
int matrix[matrix_row][matrix_col];

І так, поставити пробіл. Краще не перед, а після:

fprint(f1, "%7d ", tmp);
Подякували: SaintMal1

5

Re: Використанням файлів та потоків

Завдання №3
Зчитати символьні рядки з другого текстового файлу та здійснити їх обробку - дано 2 символьні послідовності. Вилучити з першої послідовності кожний символ, що належить другій послідовності. Вивести задані і перетворені послідовності.

int r2()
{
   FILE *f2=NULL;
    char name2[20];
    char a[40];
    char b[40];
    printf("Input file's name 2: ");
    scanf("%s", name2);
    f2 = fopen(name2, "rt");
    if (f2 == NULL)
    {
        printf("Error opening file 2\n");
        return 0;
    }
    
}

Як зчитати дві символьні послідовності та занести першу до рядка a[40],а другу до рядка b[40], для того щоб в майбутньому їх порівняти і перетворити рядок a[40]? Чи можливо є якісь інші способи, щоб вилучити з першої послідовності кожний символ, що належить другій послідовності?

6

Re: Використанням файлів та потоків

На це я вже відповідав

7

Re: Використанням файлів та потоків

У мене є файл назвою file з текстом
https://replace.org.ua/uploads/images/10577/fc37011eeb340369c6af10656a172f05.png
Я його відкриваю і хочу записати його вміст до рядка a[], тому для цього спочатку рахую кількість сивмолів в файлі а потім за допомогою алгоритму записую в рядок

int r2()
{
   FILE *f2=NULL;
    char name2[20];
    char a[40];
    char b[40];
    int i, num=0;
    printf("Введіть ім'я другого текстового файлу: ");
    scanf("%s", name2);
    f2 = fopen(name2, "rt");
    if (f2 == NULL)
    {
        printf("Не вдалось відкрити файл!\n");
        return 0;
    }
    while (fgetc(f2) != EOF)
    {
        num++;
    }
    
    for(i=0; i<num; i++)
    {
    fscanf(f2, "%c", &a[i]);   
    }

    printf("%s\n", a );

}

Але чомусь в рядок записалося "шэа"
https://replace.org.ua/uploads/images/10577/2e8a69778cdd61d70fb613701adb5181.png
В чому моя помилка?

Подякували: koala1

8 Востаннє редагувалося koala (15.11.2020 23:52:41)

Re: Використанням файлів та потоків

Дякую, тепер ясно. Файли в C - це потоки, кожна наступна операція виконується з наступним байтом файлу, тобто

a=fgetc(f2);
b=fgetc(f2);

прочитає 2 послідовні символи, це ви ніби розумієте. Але fscanf так само читатиме наступні байти за вже прочитаними, і якщо вже досягнуто кінця файлу - то читатиме якесь сміття (точніше, не читатиме, і в стрічці залишиться те сміття, що там було). Іншими словами, показчик поточного місця у файлі вже встановлено в його кінець, і нові спроби читати безглузді. Щоб виправити цей код, вам треба функцією fseek встановити показчик на початок файлу:

while(fgetc(...))
{...}
fseek(f2, 0, SEEK_SET);
for(...

Досить поширена серед студентів альтернатива - закрити і відкрити файл; дещо надмірно, але працює так само добре.
Але я б радив об'єднати цикли (трохи поганий стиль, але ідея ніби зрозуміла):

int c;
while( (c = fgetc(f2)) != EOF)
{
    a[num++] = c;
}
a[num] = '\0';

загалом fgetc та fscanf(,"%c",) - майже синонімічні; різниця в обробці помилок; ну і не слід забувати про нульовий символ наприкінці стрічки.

А ще краще - користуватися стандартними функціями:

fgets(a,40,f2);
num=strlen(a);
Подякували: SaintMal, leofun012