41

Re: Вивід рядків із масиву колонками

koala, я розумію, я глянув на input() і зрозумів, що багато чого доведеться змінювати. У мене до цього не вдавалось використовувати ці функції взагалі - проблеми виникали і я не розумів чого саме. А тут у мене вперше вдалось саме отак використати calloc(). :)

42

Re: Вивід рядків із масиву колонками

Але все ж таки пробую використати calloc() за призначенням, і ніби то вийшло, але є свої проблеми:
1. Чи можна якось покращити частину input() ?
2. В функції output() є такі моменти коли curr_gr + curr_col дають результат більший ніж nlines. Тобто коли ми заповнюємо інші колонки пробілами, то ми перше перевіряємо рядок із цієї групи, чи він зараз на позиції нуль-символу (тобто чи він повністю виведений) і якщо так - виводимо пробіли. Але трапляються ситуації, коли в ряд із 4-ьох колонок залишилось вивести тільки один рядок. Наприклад у нас 9 рядків всього. Виходить в решту три треба вивести пробіли. Але зазвичай ми перевіряємо чи решта три рядки стоять на нуль символах, але тут у нас решти взагалі немає. В принципі цю проблему можна вирішити.
Я думав додати в input() код, який би доповнював би в пам’ять іще рядки, в яких тільки нуль-символи, щоб число було пропорційно колонкам. Або зробити теж саме в output.
В цілому проблема виникає тут:

                while( curr_ch < col_width // Іще є куди записувати
                                           // і поточний рядок іще не закінчився (є іще символи)
                        && ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] != '\0')

Коли curr_gr + curr_col, дають число більше ніж nlines. Треба б просто цей шматок коду просто пропустити і перейти до виведення пробілів. Але не можу придумати рішення, щоб воно підійшло нормально, порадьте щось.
Ось код

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_NUMBER 100
#define MAX_STRING_LENGTH 128
#define MAX_COLUMNS 5
#define OUTPUT_AREA 60

/*
*
*/
int input(char **ptr);
void output(char **ptr, int nlines, int columns);

int main(int argc, char** argv) {
    int i, j, cols, nlines;
    char *lineptr[MAX_STRING_NUMBER];

    /* визначення кількості колонок */
    do{
        printf("Input number of columns (0 - default): ");
        scanf("%d", &cols);
    } while (cols < 0 || cols > MAX_COLUMNS);
    
    if (cols == 0){
        cols = 1;
    }
    
    /* читання рядків із файлу */
    nlines = input(lineptr);
    /* вивід рядків в колонки */
    output(lineptr, nlines, cols);
    
    return (EXIT_SUCCESS);
}

int input(char **lineptr){
    int c, // Приймає символ
        i; // Лічильник
    int curr_ln = 0, // Поточний рядок
        curr_ch = 0; // Поточний символ
    char buffer[MAX_STRING_LENGTH]; // Буфер для поточного рядка
    FILE *fp; // Покажчик для лексем файлу
    
    fp = fopen("user_strings.txt", "r"); // Відкриваємо файл на читання
    
    if(!fp) // Файлу немає
        return (-1);
    
    while( ((c = fgetc(fp)) != EOF)        // Йдемо до кінця файлу
            && curr_ln < MAX_STRING_NUMBER // Запобігання виходу за межі масиву
            && curr_ch < MAX_STRING_LENGTH ){
        if(c != '\r' && c != '\n' && c > 0){ // Рядок не закінчився
            buffer[ curr_ch ] = (char) c;    // Запис символу в масив
            curr_ch++;                       // Приготуємо лічильник для наступного символу
        } else if(c == '\n'){                // Рядок закінчився
            buffer[ curr_ch ] = '\0';        // Додаємо нуль-символ в кінець рядка
            lineptr[ curr_ln ] = calloc(curr_ch+1, sizeof(char));  // Виділяємо пам’ять для поточного рядка
            
            for(i = 0; i <= curr_ch; i++){
                lineptr[ curr_ln ][ i ] = buffer [ i ]; // Копіюємо поточний рядок із буфера 
                                                        // в виділену пам’ять
            }    
            
            curr_ln++;                             // Приготуємо лічильник для наступного рядка
            curr_ch = 0;                           // Обнулимо лічильник символів
        }
    }
    
    if(c == EOF && curr_ch != 0){                  // Якщо після останнього рядку не був
                                                   // поставлений символ нового рядка
        buffer[ curr_ch ] = '\0';
        lineptr[ curr_ln ] = calloc(curr_ch, sizeof(char));
        for(i = 0; i <= curr_ch; i++){
                lineptr[ curr_ln ][ i ] = buffer [ i ]; // Копіюємо поточний рядок із буфера 
                                                        // в виділену пам’ять
        }
    }
    
    fclose(fp); // Закриваємо файл
    return curr_ln;
}

void output(char **ptr, int nlines, int cols){
    char c;
    int toprint, posv[MAX_COLUMNS];
    int curr_col = 0, // Поточна колонка
        curr_ch = 0,  // Поточний символ
        last_ch = 0,  // Останній символ, який виводився із поточного рядка
        curr_gr = 0,  // Перший рядок поточної групи рядків
        col_width = ( OUTPUT_AREA - cols - 1 ) / cols; // визначення ширини колонок

    /* друк шапки */
    for(curr_col = 0; curr_col < cols; curr_col++){
        putchar('|');
        for(curr_ch = 0; curr_ch < col_width; curr_ch++){
            putchar('=');
        }
    }
    putchar('|');
    putchar('\n');
    
    /* друк колонок */
    for(curr_gr = 0; curr_gr <= nlines; curr_gr += cols){
        for(curr_col = 0; curr_col < cols; curr_col++){
            // Сюди записуються позиції,
            // на яких вивід поточного рядка був призупинений
            posv[curr_col] = 0;
        }
        toprint = 1; // Обов’язково на друк є хоча б один рядок
        while(toprint > 0){
            putchar('|');
            toprint = 0; // Поки що невідомо скільки рядків треба друкувати
            for(curr_col = 0; curr_col < cols; curr_col++){
                curr_ch = 0; // Перший символ поточного рядка
                last_ch = posv[curr_col]; // Останній символ поточного рядка
                while( curr_ch < col_width // Іще є куди записувати
                                           // і поточний рядок іще не закінчився (є іще символи)
                        && ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] != '\0'){
                    // просто друкувати по порядку
                    c = ptr[ curr_gr+curr_col ][ last_ch+curr_ch ];
                    putchar( ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] );
                    curr_ch++; // наступний символ
                }
                // Якщо цикл закінчився, але рядок іще не повністю виведений
                if(ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] != '\0'){
                    toprint++; // Треба закінчити друк іще одного рядка
                    posv[curr_col] += curr_ch; // Запам’ятовуємо місце, де ми зупинились
                } else { // В іншому разі треба запам’ятати місце нуль символу
                         // виведеного рядка, якщо якийсь із рядків групи не 
                         // повністю виведений
                    posv[curr_col] = last_ch + curr_ch;
                }
                // Якщо ми закінчили виводити рядок, а місце іще залишилось -
                // заповнюємо його пробілами
                while(curr_ch < col_width){
                    putchar(' ');
                    curr_ch++;
                }
                putchar('|');
            }
            putchar('\n');
        }
    }
}

43

Re: Вивід рядків із масиву колонками

Допомогло таке рішення: додав (curr_gr+curr_col) <= nlines в дві конструкції if, де перевіряється поточний рядок чи він не на нуль символі. Вивід нормальний, але чи це достатньо хороше рішення:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_NUMBER 100
#define MAX_STRING_LENGTH 128
#define MAX_COLUMNS 5
#define OUTPUT_AREA 60

/*
*
*/
int input(char **ptr);
void output(char **ptr, int nlines, int columns);

int main(int argc, char** argv) {
    int i, j, cols, nlines;
    char *lineptr[MAX_STRING_NUMBER];

    /* визначення кількості колонок */
    do{
        printf("Input number of columns (0 - default): ");
        scanf("%d", &cols);
    } while (cols < 0 || cols > MAX_COLUMNS);
    
    if (cols == 0){
        cols = 1;
    }
    
    /* читання рядків із файлу */
    nlines = input(lineptr);
    /* вивід рядків в колонки */
    output(lineptr, nlines, cols);
    
    return (EXIT_SUCCESS);
}

int input(char **lineptr){
    int c, // Приймає символ
        i; // Лічильник
    int curr_ln = 0, // Поточний рядок
        curr_ch = 0; // Поточний символ
    char buffer[MAX_STRING_LENGTH]; // Буфер для поточного рядка
    FILE *fp; // Покажчик для лексем файлу
    
    fp = fopen("user_strings.txt", "r"); // Відкриваємо файл на читання
    
    if(!fp) // Файлу немає
        return (-1);
    
    while( ((c = fgetc(fp)) != EOF)        // Йдемо до кінця файлу
            && curr_ln < MAX_STRING_NUMBER // Запобігання виходу за межі масиву
            && curr_ch < MAX_STRING_LENGTH ){
        if(c != '\r' && c != '\n' && c > 0){ // Рядок не закінчився
            buffer[ curr_ch ] = (char) c;    // Запис символу в масив
            curr_ch++;                       // Приготуємо лічильник для наступного символу
        } else if(c == '\n'){                // Рядок закінчився
            buffer[ curr_ch ] = '\0';        // Додаємо нуль-символ в кінець рядка
            lineptr[ curr_ln ] = calloc(curr_ch+1, sizeof(char));  // Виділяємо пам’ять для поточного рядка
            
            for(i = 0; i <= curr_ch; i++){
                lineptr[ curr_ln ][ i ] = buffer [ i ]; // Копіюємо поточний рядок із буфера 
                                                        // в виділену пам’ять
            }    
            
            curr_ln++;                             // Приготуємо лічильник для наступного рядка
            curr_ch = 0;                           // Обнулимо лічильник символів
        }
    }
    
    if(c == EOF && curr_ch != 0){                  // Якщо після останнього рядку не був
                                                   // поставлений символ нового рядка
        buffer[ curr_ch ] = '\0';
        lineptr[ curr_ln ] = calloc(curr_ch, sizeof(char));
        for(i = 0; i <= curr_ch; i++){
                lineptr[ curr_ln ][ i ] = buffer [ i ]; // Копіюємо поточний рядок із буфера 
                                                        // в виділену пам’ять
        }
    }
    
    fclose(fp); // Закриваємо файл
    return curr_ln;
}

void output(char **ptr, int nlines, int cols){
    char c;
    int toprint, posv[MAX_COLUMNS];
    int curr_col = 0, // Поточна колонка
        curr_ch = 0,  // Поточний символ
        last_ch = 0,  // Останній символ, який виводився із поточного рядка
        curr_gr = 0,  // Перший рядок поточної групи рядків
        col_width = ( OUTPUT_AREA - cols - 1 ) / cols; // визначення ширини колонок

    /* друк шапки */
    for(curr_col = 0; curr_col < cols; curr_col++){
        putchar('|');
        for(curr_ch = 0; curr_ch < col_width; curr_ch++){
            putchar('=');
        }
    }
    putchar('|');
    putchar('\n');
    
    /* друк колонок */
    for(curr_gr = 0; curr_gr <= nlines; curr_gr += cols){
        for(curr_col = 0; curr_col < cols; curr_col++){
            // Сюди записуються позиції,
            // на яких вивід поточного рядка був призупинений
            posv[curr_col] = 0;
        }
        toprint = 1; // Обов’язково на друк є хоча б один рядок
        while(toprint > 0){
            putchar('|');
            toprint = 0; // Поки що невідомо скільки рядків треба друкувати
            for(curr_col = 0; curr_col < cols; curr_col++){
                curr_ch = 0; // Перший символ поточного рядка
                last_ch = posv[curr_col]; // Останній символ поточного рядка
                while( curr_ch < col_width // Іще є куди записувати
                                           // і поточний рядок іще не закінчився (є іще символи)
                        && (curr_gr+curr_col) <= nlines
                        && ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] != '\0'){
                    // просто друкувати по порядку
                    c = ptr[ curr_gr+curr_col ][ last_ch+curr_ch ];
                    putchar( ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] );
                    curr_ch++; // наступний символ
                }
                // Якщо цикл закінчився, але рядок іще не повністю виведений
                if((curr_gr+curr_col) <= nlines 
                        && ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] != '\0'){
                    toprint++; // Треба закінчити друк іще одного рядка
                    posv[curr_col] += curr_ch; // Запам’ятовуємо місце, де ми зупинились
                } else { // В іншому разі треба запам’ятати місце нуль символу
                         // виведеного рядка, якщо якийсь із рядків групи не 
                         // повністю виведений
                    posv[curr_col] = last_ch + curr_ch;
                }
                // Якщо ми закінчили виводити рядок, а місце іще залишилось -
                // заповнюємо його пробілами
                while(curr_ch < col_width){
                    putchar(' ');
                    curr_ch++;
                }
                putchar('|');
            }
            putchar('\n');
        }
    }
}

44 Востаннє редагувалося Ярослав (10.06.2014 10:59:18)

Re: Вивід рядків із масиву колонками

Прога трохи некоректно працювала із файлом де був останній пустий рядок. Виправив:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_NUMBER 100
#define MAX_STRING_LENGTH 128
#define MAX_COLUMNS 5
#define OUTPUT_AREA 60

/*
*
*/
int input(char **ptr);
void output(char **ptr, int nlines, int columns);

int main(int argc, char** argv) {
    int i, j, cols, nlines;
    char *lineptr[MAX_STRING_NUMBER];

    /* визначення кількості колонок */
    do{
        printf("Input number of columns (0 - default): ");
        scanf("%d", &cols);
    } while (cols < 0 || cols > MAX_COLUMNS);
    
    if (cols == 0){
        cols = 1;
    }
    
    /* читання рядків із файлу */
    nlines = input(lineptr);
    /* вивід рядків в колонки */
    output(lineptr, nlines, cols);
    /* очищення пам’яті */
    for(i = 0; i < nlines; i++){
        free(lineptr[i]);
    }
    
    return (EXIT_SUCCESS);
}

int input(char **lineptr){
    int c, // Приймає символ
        i; // Лічильник
    int curr_ln = 0, // Поточний рядок
        curr_ch = 0; // Поточний символ
    char buffer[MAX_STRING_LENGTH]; // Буфер для поточного рядка
    FILE *fp; // Покажчик для лексем файлу
    
    fp = fopen("user_strings.txt", "r"); // Відкриваємо файл на читання
    
    if(!fp) // Файлу немає
        return (-1);
    
    while( ((c = fgetc(fp)) != EOF)        // Йдемо до кінця файлу
            && curr_ln < MAX_STRING_NUMBER // Запобігання виходу за межі масиву
            && curr_ch < MAX_STRING_LENGTH ){
        if(c != '\r' && c != '\n' && c > 0){ // Рядок не закінчився
            buffer[ curr_ch ] = (char) c;    // Запис символу в масив
            curr_ch++;                       // Приготуємо лічильник для наступного символу
        } else if(c == '\n'){                // Рядок закінчився
            buffer[ curr_ch ] = '\0';        // Додаємо нуль-символ в кінець рядка
            lineptr[ curr_ln ] = calloc(curr_ch, sizeof(char));  // Виділяємо пам’ять для поточного рядка
            
            for(i = 0; i <= curr_ch; i++){
                lineptr[ curr_ln ][ i ] = buffer [ i ]; // Копіюємо поточний рядок із буфера 
                                                        // в виділену пам’ять
            }    
            
            curr_ln++;                             // Приготуємо лічильник для наступного рядка
            curr_ch = 0;                           // Обнулимо лічильник символів
        }
    }
    
    if(c == EOF && curr_ch != 0){                  // Якщо після останнього рядку не був
                                                   // поставлений символ нового рядка
        buffer[ curr_ch ] = '\0';
        lineptr[ curr_ln ] = calloc(curr_ch, sizeof(char));
        
        for(i = 0; i <= curr_ch; i++){
                lineptr[ curr_ln ][ i ] = buffer [ i ]; // Копіюємо поточний рядок із буфера 
                                                        // в виділену пам’ять
        }
        
        curr_ln++;
    }
    
    fclose(fp); // Закриваємо файл
    return curr_ln;
}

void output(char **ptr, int nlines, int cols){
    char c;
    int toprint, posv[MAX_COLUMNS];
    int curr_col = 0, // Поточна колонка
        curr_ch = 0,  // Поточний символ
        last_ch = 0,  // Останній символ, який виводився із поточного рядка
        curr_gr = 0,  // Перший рядок поточної групи рядків
        col_width = ( OUTPUT_AREA - cols - 1 ) / cols; // визначення ширини колонок

    /* друк шапки */
    for(curr_col = 0; curr_col < cols; curr_col++){
        putchar('|');
        for(curr_ch = 0; curr_ch < col_width; curr_ch++){
            putchar('=');
        }
    }
    putchar('|');
    putchar('\n');
    
    /* друк колонок */
    for(curr_gr = 0; curr_gr < nlines; curr_gr += cols){
        for(curr_col = 0; curr_col < cols; curr_col++){
            // Сюди записуються позиції,
            // на яких вивід поточного рядка був призупинений
            posv[curr_col] = 0;
        }
        toprint = 1; // Обов’язково на друк є хоча б один рядок
        while(toprint > 0){
            putchar('|');
            toprint = 0; // Поки що невідомо скільки рядків треба друкувати
            for(curr_col = 0; curr_col < cols; curr_col++){
                curr_ch = 0; // Перший символ поточного рядка
                last_ch = posv[curr_col]; // Останній символ поточного рядка
                while( curr_ch < col_width // Іще є куди записувати
                        && (curr_gr+curr_col) < nlines  // і в буфері іще є рядок
                        && ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] != '\0'){ // і поточний рядок іще не закінчився (є іще символи)
                    // просто друкувати по порядку
                    c = ptr[ curr_gr+curr_col ][ last_ch+curr_ch ];
                    putchar( ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] );
                    curr_ch++; // наступний символ
                }
                // Якщо цикл закінчився, але рядок іще не повністю виведений
                if((curr_gr+curr_col) < nlines // в буфері іще є рядок
                        && ptr[ curr_gr+curr_col ][ last_ch+curr_ch ] != '\0'){ // і поточний рядок іще не закінчився (є іще символи)
                    toprint++; // Треба закінчити друк іще одного рядка
                    posv[curr_col] += curr_ch; // Запам’ятовуємо місце, де ми зупинились
                } else { // В іншому разі треба запам’ятати місце нуль символу
                         // виведеного рядка, якщо якийсь із рядків групи не 
                         // повністю виведений
                    posv[curr_col] = last_ch + curr_ch;
                }
                // Якщо ми закінчили виводити рядок, а місце іще залишилось -
                // заповнюємо його пробілами
                while(curr_ch < col_width){
                    putchar(' ');
                    curr_ch++;
                }
                putchar('|');
            }
            putchar('\n');
        }
    }
}