У меня есть набор значений в текстовом файле с разделителями как мне изменить значение с помощью программирования на C

#c #arrays #text-files

#c #массивы #текстовые файлы

Вопрос:

Текстовый файл, который у меня есть, содержит приведенные ниже данные в качестве данных (начиная с K и D и P соответственно в качестве идентификатора)

K1234: Green_Book:A_green_book:10:
K3346:Red_Book:A_red_book:7:
D3333:Grey_Book:A_grey_book:15:
D1111:Black_Book:A_black_book:1:
P0000:White_Book:A_white_book:6:

что я хотел бы сделать, так это изменить данные в строке, начинающейся с D3333, и изменить значение с 15 на 17 в текстовом файле. Я действительно не знаю, как это сделать, поскольку я новичок в программировании на C, и это беспокоит меня уже несколько дней. Я связал поиск по всей сети, но мои поиски не дали результатов. Если кто-нибудь может помочь мне с кодом, который может это сделать или что-то подобное, я был бы очень признателен. Спасибо.

Это то, что я сделал до сих пор:

 void show(){
    FILE * fl;
    long fl_size;
    char * buffer;
    size_t res;

    fl = fopen("inventItems.txt", "r ");
    if (fl == NULL) {
        fprintf(stderr, "File errorn");
        _getch();
        exit(1);
    }

    fseek(fl, 0, SEEK_END);
    fl_size = ftell(fl);
    rewind(fl);

    buffer = (char*)malloc(sizeof(char)*fl_size);
    if (buffer == NULL) {
        fputs("Memory error", stderr);
        _getch();
        exit(2);
    }

    res = fread(buffer, 1, fl_size, fl);
    if (res != fl_size) {
        fputs("Reading error", stderr);
        _getch();
        exit(3);
    }
    char * strtok_res;
    strtok_res = strtok(buffer, ":");
    while (strtok_res != NULL)
    {
        printf("%sn", strtok_res);//this prints the values from the file to a new line when i test it
        //however i DO NOT KNOW how to modify and save it back onto the text file
        strtok_res = strtok(NULL, ":");
        _getch();
    }
    _getch();
    fclose(fl);
    free(buffer);

}
  

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

1. Это проблема программирования, которую вы пытаетесь решить, чтобы научиться программировать, или это то, что вы пытаетесь сделать. Что особенного в строке, начинающейся с ‘D3333’. Вы пытаетесь написать код, который может изменить число в конце, выбрав первую комбинацию цифр и букв?

2. Это проблема программирования, которую я пытаюсь научиться решать. Это также то, что я хотел бы сделать, потому что я чувствую, что в программировании на C одной из самых сложных частей, с которыми я сталкивался, является манипулирование файлами. ‘D3333’ — это всего лишь пример строки, в которой есть значение, которое я хотел бы изменить. Чтобы ответить на ваш вопрос да, я действительно хочу иметь возможность изменить конец, выбрав первую комбинацию цифр и букв

3. ОК. Вы вообще пытались? Опубликуйте то, что вы пытались сделать до сих пор

4. код был добавлен

5. знаете ли вы какой-нибудь источник, который может помочь такому человеку, как я, который все еще относительно новичок в программировании на C?

Ответ №1:

Хорошо, похоже, вы делаете это в правильном направлении. Пара комментариев:

Повторное использование и читаемость

Вы много повторяетесь; варианты

 if(whateverPointer == NULL) {
   fprintf("My error message", stderr);
   _getch();
   exit(2);
}
  

используются в трех отдельных случаях; поэтому их следует переместить в отдельную функцию, которая принимает char* (строковое) сообщение для передачи fprintf() , чтобы вы могли просто сделать

 if(whateverPointer == NULL) {
   errorThenDeath("My message", 2);
}
  

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

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

 int changeLineValue(char** buffer, size_t size, char* identifier, int newValue) 
{
...
}
  

Обратите внимание на двойной указатель ( char** ) это указатель на оригинал char* . Когда внутри этой функции вы можете получить исходный указатель, разыменовав его ( * ) так

 *buffer = "hello";
  

Изменил бы буфер на строку «привет».

Проблема

Я не уверен, что маркировка буфера является правильным подходом. strtok на самом деле записывается символами в конце каждого токена, что затруднит при попытке записать это обратно в файл. Еще одна вещь, на которую следует обратить внимание; поскольку вы не знаете, сколько цифр может иметь ваш новый номер, вам, возможно, придется изменить размер буфера для компенсации. Сигнатура функции предполагает, что это сделано, и возвращает число, представляющее, сколько символов было добавлено или удалено (если таковые имеются).

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

 int changeLineValue(char** buffer, size_t size, char* identifier, int newValue) 
    for(int i = 0; i < size; i  ) {
        if(buffer[i] == 'n' amp;amp; isCorrectLine(*buffer, size, i)) {
           int oldVal = getCurrentValue(*buffer, size, i);
           int resize = getDigitsDifference(oldVal, value);
           if(resize != 0) {
              resizeBuffer(buffer, resize);
           }
           modifyValueInPosition(buffer, fl_size, i, value);
           return resize;
        }
    }
}
  

Примечание; из-за того, как работает язык C, isCorrectLine(...) будет вызываться только в том случае, если buffer[i] == n значение равно true. Это называется оценкой короткого замыкания.

Очевидно, что приведенный выше код вызывает пару функций, которые еще не были созданы, поэтому частью вашей задачи будет их реализация. Обратите внимание, что второй переданный параметр fl_size определяется как size_t not long even though fl_size является длинным. Вы должны изменить эту переменную на size_t .

Ниже я предоставил подписи функций. Поскольку вы пытаетесь изучить C, я не собираюсь реализовывать их для вас.

Эта функция будет вызываться каждый раз, когда встречается новая строка, с «индексом», установленным на позицию этой новой строки. Он должен возвращать 0, если идентификатор не найден в этой позиции, или 1, если он был найден в этой позиции. На данный момент ничего не меняйте в буфере

 int isCorrectLine(char* buffer, char* identifier, size_t size, int index) {
}
  

Эта функция должна выполнять итерации по строке и возвращать число перед следующим символом новой строки (‘n’)

 int getCurrentValue(char* buffer, size_t fl_size, i) {
}
  

Это число должно возвращать разницу между количеством цифр в каждом номере. Например, 1 = 1 цифра, 324 = 3 цифры, так что 3 — 1 = 2

 int digitsDifference(int old, int new) {
}
  

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

 void resizeBuffer(char** buffer, int resize) {
    *buffer = // This is how you change the original pointer. Line is still incomplete 
}
  

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

 int modifyValueInPosition(char* buffer, size_t fl_size, int index) {
}
  

Запись в файл

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

 int main() {
    // ...code that gets buffer from file. Note, make sure you close the file handle
    // afterwards it isn't good practise to leave a file handle open
    
    fl_size  = changeLineValue(buffer, fl_size, identifier, newValue);
    
    // ...Reopen file handle as you did before ...

    fwrite(buffer, sizeof(char), fl_size, fileHandle);

    // ...Close file handle...
}
  

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

1. большое спасибо за подробную иллюстрацию. я изучу это и применю в своем решении