1

I have a code here which needs to validate txt files and filter the data. I would need to use struct and realloc for my codes.

The idea here is to first read the txt file and store it in array. Then after that it will filter out the data based on the condition below. Those that meets the condition will go to data_1.txt and the others will go to error.txt.

I'm getting the error below for the struct which i'm not sure about it.

error C2440: '=' : cannot convert from 'void *' to 'Validation *'
     Conversion from 'void*' to pointer to non-'void' requires an explicit cast
error C2062: type 'void' unexpected
error C2065: 'src' : undeclared identifier
error C2065: 'dest' : undeclared identifier
error C2065: 'type' : undeclared identifier
error C2065: 'port' : undeclared identifier

Sample source file:

9001:0002:9003:0021
0001:0010:0003:0021
8001:0002:8002:0080

Source Code:

#include <stdio.h>
#include <stdlib.h>             //for exit (1)
#include <malloc.h>

struct Validation {
    int src;
    int dest;
    int type;
    int port;
    char data[50];
};

int main ()
{
    struct Validation *array;
    int option;

    FILE *inFile;               //file handle or pointer

    char filename[100];
    char test;
    int count = 0;              //keep track number of records

    int n1 = 0;                 //keep track number of correct records
    int n2 = 0;                 //keep track number of error records

    array = (struct Validation *) malloc (sizeof (struct Validation));

    do {
        printf ("Enter filename: ");
        scanf ("%s", filename);
        printf ("Processing filename %s ...\n", filename);

        inFile = fopen (filename, "r");
        if (inFile == NULL)     //check if file handler is invalid
        {
            printf ("Could not open file %s\n", filename);
            exit (1);           //error status code
        }

        test = fscanf (inFile, "%d:%d:%d:%d:",
                    &array[count].src, array[count].dest,
                    array[count].type, array[count].port);
        while (test != EOF) {
            count++;
            array = realloc (array, (count + 1) * sizeof (struct Validation));

            test = fscanf (inFile, "%d:%d:%d:%d:",
                        &array[count].src, array[count].dest,
                        array[count].type, array[count].port);
        }
    }

    void save (int, struct Validation *);
    FILE *outFile;
    FILE *errorFile;
    int i;

    outFile = fopen ("data_1.txt", "wt");
    errorFile = fopen ("data_error.txt", "wt");
    if (outFile == NULL)        //check if file handler is invalid
    {
        printf ("Could not write to file \n", filename);
        exit (1);
    }

    if (count > 0) {
        printf ("Viewing all records: ", count);
        for (i = 0; i < count;
            i++, src >= 1 && src <= 1024 && dest >= 1 && dest <= 1024
            && type >= 1 && type <= 10 && port >= 1 && port <= 1024) {
            fprintf (outFile, "%d %d %d %d", 
                    (i + 1), 
                    array[i].src,
                    array[i].dest, 
                    array[i].type, 
                    array[i].port);
            n1++;
        }
    } else {
        fprintf (errorFile, "%d %d %d %d",
                array[i].src, array[i].dest, array[i].type, array[i].port);
        n2++;
    }

    fclose (errorFile);
    fclose (outFile);
    fclose (inFile);            //must always close file once done

    free (array);

    return 0;
}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
Doran L
  • 299
  • 2
  • 5
  • 19
  • It would be useful if you indicate at which lines these errors occur, but, I'm guessing you may want to read up on C's operator precedence when you use a line like ` &array[count].src, array[count].dest, ...`. Or rather, you're missing &'s there for all but the first variable you're reading. –  Nov 19 '15 at 06:15
  • You've got a `do` without the corresponding `while` there which may throw the compiler off track. The identifiers `src`and so on are not defined as standalone variables; they can only be used as field of a struct after a dot or array operator. Then you've got a stray prototype for the `save` function in the middle of `main` but you never call `save`. And your `scanf`s must pass the addresses of the variables, not their (uninitialised) values. – M Oehm Nov 19 '15 at 06:15
  • By the way, if you just want to filter the data you can do so right away: Read a line and then decide whether you write it to the good or bad file. That would get rid of much of your code. (But if you read everyting into memory first, you are more flexible if you want to extend your program. You could, for example, sort the data before writng.) – M Oehm Nov 19 '15 at 06:23
  • Is your input line based? that is, is each entry you read on a separate line? If so, it might be a good idea to read lines first before scanning. – M Oehm Nov 19 '15 at 06:34
  • When you write out the data and the ocunt is zero, the value of ´i` is uninitialised. In that case, printing anything is a bad idea. Your filtering logic is wrong anyway. You should have an outer loop from 0 up to count (which will automatically catch the case that count is zero) and then decide with an `if`/`else` whether the current entry goes to `outFile` or to `errorFile`. Putting that condition into the `for` condition will stop your loop short on the first wrong entry. – M Oehm Nov 19 '15 at 06:37

1 Answers1

3

With all of the errors in this program, I can only conclude that the resource you're using to learn C isn't working; it's teaching you all sorts of errors, both the kind that prevent your program from compiling and the kind that prevent your program from functioning correctly. I suggest reading K&R 2nd edition, and doing the exercises, before you go any further with this program.


For a start, your project contains some serious syntax errors which you'll spot when you fix up your indentation. If you don't know how to do that, consider studying this wiki page on indent styles.


The latter four of your errors are in this line:

for (i = 0; i < count; i++, src >= 1 && src <= 1024 && dest >= 1 && dest <= 1024 && type >= 1 && type <= 10 && port >= 1 && port <= 1024)
                          ^----------

For a start, your errors are telling you that src, dest, type and port are undeclared. Perhaps you meant to write array[i].src, array[i].dest, array[i].type and array[i].port...

The comma I'm pointing at probably doesn't mean what you think it does. Even if you fix the errors in this line, everything after that comma has no effect on this code at all, and so your loop is effectively:

for (i = 0; i < count; i++)

I can only hazard a guess, but perhaps a for (pre-test) loop isn't appropriate for your needs, and you should be using an if (part_of_test) do { ... } while (test); idiom, instead? Perhaps that is excessive, and you could write the required functionality solely using a do { ... } while (test); idiom.


while (test != EOF)

This loop is erroneous, too. If you want to ensure that four decimal-digit integers were correctly read from inFile, you need to make sure test is equal to 4, which is not the same as making sure test is inequal to EOF. For example:

while (test == 4)

Moving on, you seem to be attempting to compile your C code as C++.

While it is true that some C code is also valid in C++, you have come across an example of C code that isn't valid in C++.

That is, C++ does not offer the implicit conversions to/from void * that C does.


You should always compile your C code using a C compiler, for the following three reasons:

  • You don't need to compile C code using a C++ compiler.
  • You're missing out on the best parts of C++.
  • You're missing out on the best parts of C.

The only reason people try to compile C code with a C++ compiler is that they anticipate using their C code in a C++ project. However, this is unnecessary because you can usually compile your C code using a C compiler, compile your C++ code using a C++ compiler and then link the two together. For example:

gcc -c c_code.c
g++ -c cpp_code.cpp
gcc cpp_library.o c_library.o

If you're using Microsoft Visual Studio, separate your C source code into a different project and browse through the project settings looking for a "Compile as C code" option. If your project is C only, you can ignore the remainder of this paragraph... Otherwise your project is mixed C and C++. While you're browsing, keep an eye open for "linking" and "project dependencies" settings; you'll want to set up your C project as a dependency for your C++ project. You might also want to introduce some "linking directories" (or paths, I forget the precise term) and/or "include directories".


In C++, it is generally a bad idea to use void * pointers (and you should probably use new instead of malloc). Not to mention, you should avoid using the *scanf family of functions. Those who program specifically in C++ will usually cringe at these practices, because templates and operator overloading virtually eliminate all of the valid usecases for them in a way that makes corresponding C++ code less error-prone and straight forward to read and write.


In C, it is always a bad idea to explicitly cast void * (and you should eliminate the void * casts you currently use), as the answer to this question explains. Those who program specifically in C will cringe at unnecessary boilerplate that potentially introduces bugs.

autistic
  • 1
  • 3
  • 35
  • 80