简体   繁体   English

C 程序 - 从文件中读取整数并解码秘密消息

[英]C Program - reading integers from a file and decoding secret message

Hey:) I need some help with my code, which I think is mostly correct but I am having trouble figuring out where I am going wrong.嘿:) 我的代码需要一些帮助,我认为这大部分是正确的,但我无法弄清楚我哪里出错了。

#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);
}

I added some print functions to trouble shoot, and during the load_nums function the printf functions continuously prints 0's, it is not reading in the correct integer values from the file pointed to.我添加了一些打印功能来排除故障,在 load_nums function 期间,printf 函数连续打印 0,它没有从文件中读取正确的 Z157DB7DF530023575515ZD366C9B672E 值。

Could any of you help particularly with the load_nums function?你们中的任何人都可以特别帮助 load_nums function 吗? Thank you all and let me know if you need any extra information.谢谢大家,如果您需要任何额外信息,请告诉我。 "-6 -76 53 -34 32 79 142 55 177 78" is what is in the file pointed to. “-6 -76 53 -34 32 79 142 55 177 78”是文件中指向的内容。

You are making things much more complicated than they need to be.你让事情变得比他们需要的复杂得多。 You are dynamically allocating storage for both codedPtr and decodedPtr , there is no need to make two passes through the file (one to count integers, and one to read after allocation).您正在为codedPtrdecodedPtr动态分配存储空间,无需两次通过文件(一次用于计算整数,一次用于在分配后读取)。 Your decode is much more complex than necessary and there is a logic error.您的decode比必要的复杂得多,并且存在逻辑错误。 Adding '0' (it's not necessary in this case -- though normally it is to convert a decimal digit to its ASCII character value)添加'0' (在这种情况下没有必要——尽管通常是将十进制数字转换为其 ASCII 字符值)

To address load_nums , change the return type to int * and allocate for codedPtr within load_nums using realloc as needed to increase the size of your allocated block of memory.要解决load_nums ,请将返回类型更改为int *并根据需要使用realloccodedPtr中的load_nums分配,以增加 memory 分配块的大小。 Then return a pointer to the allocated block of memory holding your int values.然后返回指向 memory 的已分配块的指针,该块保存您的int值。 Pass ncount as a pointer (eg int *ncount ) so you can update the value at that address with the number of integers read so that the count is available back in the calling function ( main() here).ncount作为指针传递(例如int *ncount ),以便您可以使用读取的整数数更新该地址的值,以便在调用 function (此处为main() )中可以使用计数。

Approaching allocation in this manner reduces your file I/O to a single-pass through the file (and file I/O is one of the most time consuming operations) Further, you completely eliminate the need for a num_count() function.以这种方式进行分配可将文件 I/O 减少为单次通过文件(文件 I/O 是最耗时的操作之一)此外,您完全不需要num_count() function。

Putting those pieces together, you could do:将这些部分放在一起,您可以执行以下操作:

/* 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 */
}

You would call the function in main() as, codedPtr = load_nums (fp, &numCount) .您可以将main()中的 function 称为codedPtr = load_nums (fp, &numCount) You can wrap it in an if(...) statement to determine whether the allocation and read succeeded or failed:您可以将其包装在if(...)语句中以确定分配和读取是成功还是失败:

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

(there is no need to pass codedPtr from main() . You can further validate by checking numCount > 0 -- that is left to you) (无需从main()传递codedPtr 。您可以通过检查numCount > 0来进一步验证——这留给您)

For your decode function, simply set up the for loop use two loop variables to iterate from the beginning and end towards the middle.对于您的decode function,只需设置for循环,使用两个循环变量从开头和结尾向中间迭代。 This greatly simplifies things, eg这大大简化了事情,例如

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 starts at the first integer value and j at the last. Don't use *(codePtr + i) instead use codePtr[i] -- though equivalent, index notation is easier to read) i从第一个 integer 值开始,最后是j 。不要使用*(codePtr + i)而是使用codePtr[i] - 虽然等效,但索引符号更易于阅读)

In main() you can alternatively open the file provided as the first argument to your program or read from stdin by default if no argument is provided (this is the way many Linux utilities work).main()中,您可以选择打开作为程序第一个参数提供的文件,或者如果没有提供参数,则默认从标准输入读取(这是许多stdin实用程序的工作方式)。 Adding a simple ternary is all you need.您只需要添加一个简单的三元组 Whether you are reading input or allocating memory (or using any function that is necessary for the continued correct operation of your code), you cannot use that function correctly unless you check the return to determine if the operation succeeded or failed.无论您是读取输入还是分配 memory(或使用任何 function 对代码的持续正确操作都是必需的),您都不能使用该 ZC1C425268E68385D1AB5074C17A94F14 来确定操作是否正确,除非您检查返回是否正确。 Lesson: validate, validate, validate... .课程:验证,验证,验证......

Putting it altogether, you could do:总而言之,你可以这样做:

#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);
}

Example Use/Output示例使用/输出

Testing your program, you find the decoded message is "Hello" , eg测试你的程序,你发现解码的消息是"Hello" ,例如

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

Memory Use/Error Check Memory 使用/错误检查

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.在您编写的任何动态分配 memory 的代码中,对于分配的 memory 的任何块,您有两个责任:(1)始终保留指向 ZCD69B4957F06CD818D7BF3D61980 块的起始地址的指针,所以它可以被释放,需要更长的时间。

It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.您必须使用 memory 错误检查程序,以确保您不会尝试访问 memory 或写入超出/超出分配块的边界,尝试读取或基于未初始化值的条件跳转,最后确认释放所有已分配的 memory。

For Linux valgrind is the normal choice.对于 Linux valgrind是正常的选择。 There are similar memory checkers for every platform.每个平台都有类似的 memory 检查器。 They are all simple to use, just run your program through it.它们都易于使用,只需通过它运行您的程序即可。

$ 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)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.始终确认您已释放所有已分配的 memory 并且没有 memory 错误。

Look things over and let me know if you have further questions.如果您还有其他问题,请仔细查看并告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM