Добавить цифры к имени файла - PullRequest
0 голосов
/ 31 мая 2019

Я хочу хранить данные в разных файлах.Поэтому я хочу создать файлы следующим образом: data_1.log, data_2.log, ..., data_N.log.Приложение .log не обязательно, но было бы неплохо.Все мои подходы пока не увенчались успехом.Вот один пример, который, вероятно, близок к тому, что мне нужно:

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

char get_file_name(int k){ 
    int i, j;
    char s1[100] = "logs/data_";
    char s2[100];
    snprintf(s2, 100, "%d", k);
    for(i = 0; s1[i] != '\0'; ++i);
    for(j = 0; s2[j] != '\0'; ++j, ++i){
        s1[i] = s2[j];
    }
    s1[i] = '\0';
    return s1;
}

int main(){

    char file_name[100];
    for(int k=0; k<10; k++){
        // Get data
        // ...
        // Create filename
        strcpy(file_name, get_file_name(k));
        printf("%s", file_name);
        // fp = fopen(file_name, "w+");
        // Write data to file
        // print_results_to_file();
        // fclose(fp);
    }

    return 0;
}

На данный момент я получаю следующие ошибки, которые я не понимаю:

    string.c: In function ‘get_file_name’:
string.c:14:12: warning: returning ‘char *’ from a function with return type ‘char’ makes integer from pointer without a cast [-Wint-conversion]
     return s1;
            ^~
string.c:14:12: warning: function returns address of local variable [-Wreturn-local-addr]
string.c: In function ‘main’:
string.c:24:27: warning: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
         strcpy(file_name, get_file_name(k));
                           ^~~~~~~~~~~~~~~~
In file included from string.c:2:
/usr/include/string.h:121:14: note: expected ‘const char * restrict’ but argument is of type ‘char’
 extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
              ^~~~~~

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

Ответы [ 4 ]

2 голосов
/ 31 мая 2019

Существуют различные проблемы с этим кодом, и вместо того, чтобы исправлять их один за другим, предлагается альтернативный подход. Он не единственный, но он прост и должен быть легок для понимания и адаптации:

#include <stdio.h>

void get_file_name(int k, char* buffer, size_t buflen) {
    snprintf(buffer, buflen, "logs/data_%d.log", k);
}

int main() {
    const size_t BUFLEN = 50;
    char file_name[BUFLEN];

    for (int i = 0; i < 10; i++) {
        get_file_name(i, file_name, BUFLEN);
        printf("%s\n", file_name);
        // Code for writing to file.
    }
}

Несколько деталей:

  1. Вместо того, чтобы пытаться вернуть (указатели) память, эта функция передает буфер, в который записывается. Вызывающий должен убедиться, что буфер достаточно большой (это всегда так, но если фактические имена файлов длиннее, вы должны добавить логику, которая проверяет возвращаемое значение snprintf и выполняет соответствующую обработку ошибок).

  2. Фактическая логика функции требует только одного вызова snprintf, который уже выполняет все, что вам нужно, поэтому неясно, является ли наличие отдельной функции даже необходимым или полезным.

  3. Выше используются массивы переменной длины. Если вы хотите обеспечить постоянные буферы, вы можете использовать #define вместо const size_t переменной для длины буфера. Однако, использование массива переменной длины здесь хорошо, и некоторые компиляторы даже конвертируют его в постоянный массив.

Как уже упоминалось в комментариях, важно, чтобы вы (а) читали и понимали документацию по функциям, которые вы используете, и (б) читали и понимали сообщения об ошибках компилятора.

2 голосов
/ 31 мая 2019

Функция get_file_name имеет тип возврата char

char get_file_name(int k){

но возвращает объект типа char *

char s1[100] = "logs/data_";
//...
return s1;

Кроме того, возвращаемый указатель указывает на локальный массив s1, который не будет работать после выхода из функции.

В этом звонке

strcpy(file_name, get_file_name(k));

тип второго аргумента (то есть char согласно объявлению функции get_file_name) должен быть char *.

Нет ни объявления функции print_results_to_file, ни ее определения.

В соответствии со стандартом C функция main без параметров должна быть объявлена ​​как

int main( void )

Я бы написал функцию get_file_name следующим образом

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

char * get_file_name( char *file_name, size_t n, size_t padding )
{
    const char *common_part = "logs/data_";

    snprintf( file_name, n, "%s%zu", common_part, padding );

    return file_name;
}    

int main( void )
{
    enum { N = 100 };
    char file_name[N];

    for ( size_t i = 0; i < 10; i++ ) puts( get_file_name( file_name, N, i ) );
}

Вывод программы

logs/data_0
logs/data_1
logs/data_2
logs/data_3
logs/data_4
logs/data_5
logs/data_6
logs/data_7
logs/data_8
logs/data_9
0 голосов
/ 31 мая 2019

Ваши ошибки легко объяснимы:

get_file_name должен вернуть char, но вы создаете char[] и возвращаете это (это то же самое, что char*)

get_file_name возвращает адрес массива, созданного в самой функции.После завершения функции массив может быть перезаписан.Добавить массив в качестве параметра или использовать malloc

strcpy не работает, поскольку он ожидает char* (char[]), а не char.get_file_name возвращает char.

print_results_to_file не определено.Вам может потребоваться включить другие файлы, которые вы используете в программе (например, если функция реализована в файле func.c, прототип должен находиться в файле с именем func.h, который включается через #include "func.h".

0 голосов
/ 31 мая 2019

Есть несколько проблем с вашим кодом, но самая большая из них заключается в том, что вы пытаетесь вернуть указатель на локальную переменную из get_file_name.

Это большое нет, так как память выделена дляchar s1[100] в get_file_name освобождается сразу после return.

Остальные ошибки связаны с тем, что вы забыли * в char get_file_name(int k).

Существует несколько возможных решений.:

  1. Передайте массив char для функции, которую нужно заполнить.
  2. Используйте глобальную переменную (это считается плохой практикой).
  3. Динамическое выделениепамяти.
  4. Сделать локальную переменную статической (это немного глупо, но допустимо)
...