C Программа - чтение целых чисел из файла и расшифровка секретного сообщения - PullRequest
0 голосов
/ 10 апреля 2020

Привет :) Мне нужна помощь с моим кодом, который я считаю в основном правильным, но у меня возникают проблемы с выяснением, где я ошибаюсь.

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

int num_count(FILE* ptr){
    int count = 0;
    int numHolder = 0;
    while((fscanf(ptr, "%d", &numHolder)) == 1){
     count++;
    }
    return count;
}

void load_nums(FILE* ptr, int *codedPtr, int ncount){
    int number = 0;
    ncount = ncount - 1;
    for(int i = 0; i <= ncount; i++){
     fscanf(ptr, "%d", &number);
     printf("%d", number);
     *(codedPtr + i) = number;
    }
    return;
}

void decode(int *codedPtr, int ncount, char *decodedPtr){
    char temp;
    ncount = ncount - 1;
    for(int i = 0; i <= ncount; i++){
     temp = ((*(codedPtr + i) + *(codedPtr + (ncount - i))) + '0');
     *decodedPtr = temp;
     decodedPtr++;
    }
    return;
}

int main(int argc, char *argv[]){
    int *codedPtr;
    char *decodedPtr;
    FILE *fp;

    if (argc == 2){
     fp = fopen(argv[1], "r+");
    }
    if(argc <= 1){
     printf("Invalid command line: cmd infile outfile\n");
    }
    int numCount = num_count(fp);
    printf("%d", *codedPtr);
    codedPtr = (int*)calloc(numCount, sizeof(int));
    decodedPtr = (char*)calloc(numCount, sizeof(char));
    load_nums(fp, codedPtr, numCount);
    decode(codedPtr, numCount, decodedPtr);
    printf("\n%s\n\n", decodedPtr);
    fclose(fp);
    return(0);
}

Я добавил некоторые функции печати для устранения неполадок и во время функции load_nums функция printf непрерывно печатает 0, она не считывает правильные целочисленные значения из указанного файла.

Может ли кто-нибудь из вас помочь, особенно с функцией load_nums? Спасибо всем и дайте мне знать, если вам нужна дополнительная информация. «-6 -76 53 -34 32 79 142 55 177 78» - это то, на что указано в файле.

1 Ответ

0 голосов
/ 10 апреля 2020

Вы делаете вещи намного сложнее, чем они должны быть. Вы динамически распределяете память для codedPtr и decodedPtr, нет необходимости делать два прохода по файлу (один для подсчета целых чисел и один для чтения после выделения). Ваш decode намного сложнее, чем необходимо, и есть ошибка logi c. Добавление '0' (в этом случае нет необходимости - хотя обычно требуется преобразовать десятичное значение di git в его символьное значение ASCII)

Для адреса load_nums измените тип возврата - int * и выделить для codedPtr в пределах load_nums, используя realloc по мере необходимости, чтобы увеличить размер выделенного блока памяти. Затем верните указатель на выделенный блок памяти, содержащий ваши значения int. Передайте ncount в качестве указателя (например, int *ncount), чтобы вы могли обновить значение по этому адресу числом прочитанных целых чисел, чтобы счет был доступен обратно в вызывающей функции (main() здесь).

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

Соединяя эти части вместе, вы можете сделать:

/* read integers from fp, dynamically allocating storage as needed,
 * return pointer to allocated block holding integers and make ncount
 * available through update pointer value.
 */
int *load_nums (FILE* fp, int *ncount)
{
    int *codedPtr, avail = 2;   /* declare pointer & no. to track allocated ints */
    *ncount = 0;                /* zero the value at ncount */

    /* allocate avail no. of int to codedPtr - validate EVERY allocation */
    if (!(codedPtr = malloc (avail * sizeof *codedPtr))) {
        perror ("malloc-codedPtr");
        return NULL;
    }

    while (fscanf (fp, "%d", &codedPtr[*ncount]) == 1) {    /* read each int */
        if (++(*ncount) == avail) { /* check if realloc needed (count == avail) */
            /* always realloc to a temporary pointer */
            void *tmp = realloc (codedPtr, 2 * avail * sizeof *codedPtr);
            if (!tmp) {             /* validate that realloc succeeds */
                perror ("realloc-codedPtr");
                return codedPtr;    /* original codedPtr vals available on failure */
            }
            codedPtr = tmp;         /* assign new block of mem to codedPtr */
            avail *= 2;             /* update avail with no. of int allocated */
        }
    }

    return codedPtr;    /* return pointer to allocated block of memory */
}

Вы бы вызвали функцию в main() as, codedPtr = load_nums (fp, &numCount). Вы можете заключить его в оператор if(...), чтобы определить, успешно ли выполнено выделение и чтение:

    int *codedPtr = NULL, numCount = 0;
    ...
    if (!(codedPtr = load_nums (fp, &numCount)))    /* read file/validate */
        return 1;

(нет необходимости передавать codedPtr из main(). Дальнейшую проверку можно выполнить с помощью проверка numCount > 0 - это вам осталось)

Для вашей функции decode просто установите for l oop, используйте две переменные l oop для итерации с начала и до конца к середине. Это значительно упрощает ситуацию, например,

void decode (int *codedPtr, int ncount, char *decodedPtr)
{
    /* loop from ends to middle adding values, + '0' NOT required */
    for (int i = 0, j = ncount - i - 1; i < j; i++, j--)
        decodedPtr[i] = codedPtr[i] + codedPtr[j];
}

(i начинается с первого целого числа и j - до последнего. Не используйте *(codePtr + i) вместо использования codePtr[i] - хотя и эквивалентно, индексную нотацию легче читать)

В main() вы можете альтернативно открыть файл, предоставленный в качестве первого аргумента вашей программе, или прочитать из stdin по умолчанию, если аргумент не предоставлен (так много Linux утилиты работают). Добавление простого троичного - это все, что вам нужно. Читаете ли вы ввод или выделяете память (или используете какую-либо функцию, необходимую для продолжения правильной работы вашего кода), вы не сможете использовать эту функцию правильно, если вы не проверили возврат в определить, была ли операция успешной или неудачной. Урок: валидация, валидация, валидация ... .

В целом, вы можете сделать:

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

/* read integers from fp, dynamically allocating storage as needed,
 * return pointer to allocated block holding integers and make ncount
 * available through update pointer value.
 */
int *load_nums (FILE* fp, int *ncount)
{
    int *codedPtr, avail = 2;   /* declare pointer & no. to track allocated ints */
    *ncount = 0;                /* zero the value at ncount */

    /* allocate avail no. of int to codedPtr - validate EVERY allocation */
    if (!(codedPtr = malloc (avail * sizeof *codedPtr))) {
        perror ("malloc-codedPtr");
        return NULL;
    }

    while (fscanf (fp, "%d", &codedPtr[*ncount]) == 1) {    /* read each int */
        if (++(*ncount) == avail) { /* check if realloc needed (count == avail) */
            /* always realloc to a temporary pointer */
            void *tmp = realloc (codedPtr, 2 * avail * sizeof *codedPtr);
            if (!tmp) {             /* validate that realloc succeeds */
                perror ("realloc-codedPtr");
                return codedPtr;    /* original codedPtr vals available on failure */
            }
            codedPtr = tmp;         /* assign new block of mem to codedPtr */
            avail *= 2;             /* update avail with no. of int allocated */
        }
    }

    return codedPtr;    /* return pointer to allocated block of memory */
}

void decode (int *codedPtr, int ncount, char *decodedPtr)
{
    /* loop from ends to middle adding values, + '0' NOT required */
    for (int i = 0, j = ncount - i - 1; i < j; i++, j--)
        decodedPtr[i] = codedPtr[i] + codedPtr[j];
}

int main(int argc, char *argv[]) {

    int *codedPtr = NULL, numCount = 0;
    char *decodedPtr = NULL;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    if (!(codedPtr = load_nums (fp, &numCount)))    /* read file/validate */
        return 1;

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    if (!(decodedPtr = malloc (numCount + 1))) {    /* allocate/validate */
        perror ("malloc-decodedPtr");               /* don't forget room for '\0' */
        return 1;
    }

    decode (codedPtr, numCount, decodedPtr);        /* decode the message */
    decodedPtr[numCount] = 0;                       /* nul-terminate */

    puts (decodedPtr);                              /* output decoded message */

    free (codedPtr);        /* don't forge to free what you allocate */
    free (decodedPtr);
}

Пример использования / Вывод

Тестируя вашу программу, вы обнаруживаете, что декодированное сообщение равно "Hello", например,

$ echo "-6 -76 53 -34 32 79 142 55 177 78" | ./bin/codedptr
Hello

Проверка использования памяти / ошибок

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

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

Для Linux valgrind это нормальный выбор. Есть похожие проверки памяти для каждой платформы. Все они просты в использовании, просто запустите вашу программу через нее.

$ echo "-6 -76 53 -34 32 79 142 55 177 78" | valgrind ./bin/codedptr
==32184== Memcheck, a memory error detector
==32184== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32184== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==32184== Command: ./bin/codedptr
==32184==
Hello
==32184==
==32184== HEAP SUMMARY:
==32184==     in use at exit: 0 bytes in 0 blocks
==32184==   total heap usage: 7 allocs, 7 frees, 5,251 bytes allocated
==32184==
==32184== All heap blocks were freed -- no leaks are possible
==32184==
==32184== For counts of detected and suppressed errors, rerun with: -v
==32184== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

...