Как написать текст, содержащий новую строку, заданную в качестве аргументов командной строки в C?

#c #newline #command-line-arguments #system-calls #file-handling

#c #новая строка #аргументы командной строки #системные вызовы #обработка файлов

Вопрос:

Я хочу создать текстовый файл с несколькими строками, используя системные вызовы на C, и заполнить его текстом, предоставленным в качестве аргументов командной строки.

Это то, что я написал:

 #include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX_SZ 1024

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Invalid Number of argumentsn");
        printf("USAGE: ./a.out file_name "msg"n");
    } else {
        int fd_creat, fd_open, fd_write;
        char file_name[MAX_SZ];
        char *msg = (char *)malloc(strlen(argv[2]) * sizeof(char));
        strcpy(file_name, argv[1]);
        fd_creat = creat(file_name, 0777);
        if (fd_creat < 2) {
            printf("ERROR: File could not be createdn");
        } else {
            fd_open = open(file_name, O_WRONLY);
            strcpy(msg, argv[2]);
            fd_write = write(fd_open, msg, strlen(msg));
            close(fd_open);
        }
    }
    return 0;
}
  

Если я выполню эту программу как:

 ./a.out test.txt "FoonBar"
  

Он записывает все это в test.txt как оно есть. В принципе, я хочу, чтобы «Foo» и «Bar» были в отдельных строках.

Комментарии:

1. Возможно, вы захотите использовать PATH_MAX для путей. При этом, почему вы копируете аргумент в буфер, но не меняете его? Чем это лучше, чем просто argv[1] прямое использование?

2. Вы делаете это снова с argv[2] помощью . Возможно, это результат ошибочного предположения, что вам нужно скопировать argv значения перед их использованием, но это не так.

3. Также нет необходимости вызывать creat . Просто откройте файл в режиме записи и начните запись. В C вы, как правило, захотите использовать функции на FILE* основе, например fopen , вместо низкоуровневой open функции.

4. Вам нужен еще один элемент для обозначения нулевого символа msg .

5. Чтобы сделать код читаемым без ненужного выделения и копирования памяти, просто выполните char *file_name = argv[1]; и char *msg = argv[2];

Ответ №1:

Здесь есть две проблемы:

  • То, как вы обрабатываете аргументы и не выделяете достаточно памяти для задействованных данных,
  • Интерпретация escape-последовательностей, подобных n правильной, поскольку оболочка предоставит их вам как есть, в необработанном виде.
 #include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

// This moves overlapping strings from src -> dest but only
// if dest is before src
void cc_str_drag(char* dest, char* src) {
    while (*dest) {
        *dest = *src;
          dest;
          src;
    }
}

// This interprets the n sequence and can be extended to handle others, like
// t, \, or even g.
void cc_interpret(char* str) {
    for (;*str;   str) {
        // If this is a sequence start...
        if (*str == '\') {
            // ...find out which one...
            switch (str[1]) {
                case 'n':
                    // Shift back...
                    cc_str_drag(str, amp;str[1]);
                    // ...and replace it.
                    *str = 'n';
                    break;
            }
        }
    }
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Invalid Number of argumentsn");

        // Remember argv[0] is the name of the program
        printf("USAGE: %s file_name "msg"n", argv[0]);
        return -1;
    }

    // Since it's not the 1970s, use fopen() and FILE*
    FILE* output = fopen(argv[1], "w");

    if (!output) {
        printf("ERROR: File could not be createdn");
        return -2;
    }

    // Copying here to avoid tampering with argv
    char* str = strdup(argv[2]);

    // Replace any escape sequences
    cc_interpret(str);

    // Then just dump it directly into the file
    fwrite(str, 1, strlen(str), output);

    fclose(output);

    return 0;
}
  

Обратите внимание на используемые здесь инструменты:

  • strdup это более быстрый способ копирования строки C, чем malloc(strlen(s)) ее последующее копирование. Это вызывает страшные единичные ошибки.
  • FILE* работает намного лучше, потому что он буферизован. open() используется для низкоуровневых операций, которые нельзя буферизировать. Знайте, когда использовать какой инструмент.
  • Не бойтесь писать функции, которые управляют строковым содержимым. Строки C действительно важно понимать, а не бояться.

Комментарии:

1. В вашем коде была одна небольшая ошибка, хотя для ввода: «Foo nBar», ваш код выдавал «Foo» и «arr» в отдельных строках, я изменил «strcpy (str, amp;str[1]);» с «strcpy (amp;str[1], amp;str [2]);» чтобы получить желаемый результат («Foo» и «Bar» в отдельных строках). Спасибо за вашу помощь!

2. Я протестировал это как есть, и это сработало для меня, создав правильный вывод и для этого, так что, возможно, что-то немного отличается в вашей версии. Рад, что это сработало! Возможно, что использование strcpy() для перемещения объектов в такой строке недопустимо, я написал свой собственный транспозиционер строк, но удалил его в последнюю секунду, подумав, что это strcpy может сработать.

3. В документации указано: «Поведение не определено, если строки перекрываются». это то, о чем я беспокоился.

4. Я вернул туда функцию перемещения строк.