Hi there^^ Its my first post on these forums, and as much as I hate it to be a shout for help ive got a problem I could really use someone with a bit of knowledge to help me out with =)

My scenario being ive got to write a code that asks the user for input from a file (in this particular case it will be a number of folat values in .txt format), scan them into an array, and manipulate said array with a few mathematical functions, and whack it through a final calculation to give a value output to the screen.

Right now ive spent days and days trying to code the first part correctly, and its kicking my ass (Im new to any form of programming!). I could make it more basic by defining the array size, but I actually find all this quite interesting, so id rather learn the hard way :cheesy:


Anyway, without further ado, here's what ive got so far, and no, it doesnt work =P

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
    FILE *fp;
    char ch, *filename (char *buf, size_t length, FILE *f);
    long lSize;
    float *buffer;
 
int main(int argc, char *argv[])
{
#define initial_value 0.07
#define increment 0.125
    while (1)
    {
        // Input filename.
        printf("\nEnter a filename: ");
        gets(*filename);
        // Try to open the file.
        if ( (fp = fopen(filename, "r")) == NULL )
        {
            perror("\nError opening file");
            puts("\nEnter x to exit, any other to try again.");
            if ( (ch = getch()) == 'x')
                break;
        }
        else
        {
            // obtain file size.
            fseek (fp , 0 , SEEK_END);
            lSize = ftell (fp);
            rewind (fp);
            // allocate memory to contain the whole file.
            buffer = (float*)malloc(lSize);
            if (buffer == NULL) exit (EXIT_FAILURE);
                else printf("\n%d bytes of memory allocated to file...\n", lSize);
                    printf("\nSuccessful opened %s!\n", filename);
 
            // copy the file into the buffer.
 
 
            // terminate
            fclose (fp);
            free (buffer);
            puts("\nEnter x to exit, any other to continue.");
            if ( (ch = getch()) == 'x')
                break;
        }
 
    }
}
//--------------FUNCTIONS--------------
 
char *filename (char *buf, size_t length, FILE *f)
{
    char buf[40], *p;
    if (p = fgets (buf, length, f))
    {
        size_t last = strlen (buf) - 1;
        if (buf[last] == '\n') {
            buf[last] = '\0';
        }
        else {
            fscanf (f, "%*[^\n]");
            (void) fgetc (f);
        }
    }
    return p;
}

The function gives me the following errors:

19: error: cannot convert `char*(*)(char*, size_t, FILE*)' to `const char*' for argument `1' to `FILE* fopen(const char*, const char*)'
57: error: declaration of 'char buf[40]' shadows a parameter
:: === Build finished: 2 errors, 0 warnings ===

If i hash out the function, and simply replace the *filename code in line 7 with

filename[40];

it works fine!

Also, I cant tell if the code for buffer is working or not, it seems to be, but im too new to all this to tell, until i write the file into an array (which I cant do yet since I do not know how do define an array size for a file that can be of different sizes...)

The code for the array will go in the middle of the program, where ive left room for it under

// copy the file into the buffer.

Im sorry, that was a real mouthful, any help would be greatly appreciated ^^

Chris

edit: you can ignore the define's for now, theyre to be used in the calculations later on =)

Recommended Answers

All 13 Replies

First of all, let me say that if you're new to programming you've done a great job with 'neatness' of code. It's so nice to see code with comments. :).
Anyway..
A few questions I have before I can answer..
1. Is it mandatory for u to use C? Can't u use C++? It would a LOT easier with C++ STL n all..
2. Is you file an ascii file or a binary/data file? May not be related to your problem but see http://bama.ua.edu/cgi-bin/man-cgi?fopen+3C. Ideally you should opne with "rb" as the mode. (could run into to unwanted problem otherwise depending on environment, i.e. unix/windows..)


Now to the code, a few things I think you can correct.
Line 7:

char ch, *filename (char *buf, size_t length, FILE *f);

It seems to me like compiler is not cribbing at line 7 itself (although it should), only because it thinks that you have correctly declared
1. char ch; = ch as a character
2. char *filename (char *buf, size_t length, FILE *f); = prototype/declaration for a function named "filename" (which is defined on line 55).
Function names are nothing but variables of type "function pointers". So when you use this function as an argument to gets() on line #19 compiler tries to match the expected type (char*) and supplied type (char*(*)(char*, size_t, FILE*)). As they don't match compiler tries to convert supplied type to the expected type using built-in (and user-defined, viz not applicable in your case) conversion operators/rules. In this case a pointer to function pointer can't be converted to char* so compiler gives an error.

When you change filename's declaration to filename[40]. Compiler sees "filename" as a "char*" which is exactly what is required by gets().

So first thing you can correct is: declare filename as char filename[40] .

Second problem with the code is that you have opened the file in text /ascii mode and you are allocating teh buffer (into which you plan to read the data) as if the file is a binary/data file. The way data is stored in binary/data file is different than an ascii file (See http://www.learn-programming.za.net/programming_c_learn10.html)
. In simple words if your file is a binary/data file then sizeof buffer to be allocated would be same as size of file (or number of bytes ni file). But if file is an ascii file that is not true. (if a single number say 1000 is stored in an ascii file file size would be 4 bytes, if it's stored in a binary file it'll be sizeof(int) ).

Third and biggest problem is you have a function AND a variable with same name (after you make the suggested correction) ! This is NEVER a good idea. Remember the rule of thumb "Never use/introduce/declare same name twice in same scope." Name here refers to a variable/function/struct-type...
So pick any one naming notation/convention of you choice and follow it. E.g. hungarian is a famous one. If you are not comfortable with that at least think of a story like name for your variables for they dn't clash. E.g. change char filename[40] to char input_filename[40] .
The other error "57: error: declaration of 'char buf[40]' shadows a parameter" is that char buf[40] declared on line 57 hides the other variable in same scope which is teh function argument char *filename ( char *buf , size_t length, FILE *f) . May be you can change line 57 to char* tmp_buf

Hey there, thanks a lot for the reply and initial suggestions, ill get on it as soon as I can and post up an appended version!

To answer you're initial few questions, i have to use C :( I wish I could use C++, since it seems to bemuch better for dynamic memory allocation ><

Secondly, the program has to read text not binary (which explains a poblem you touched on later in your reply^^)

Be back in a bit *open up compiler* x_x

Chris

Hi there^^ Its my first post on these forums, and as much as I hate it to be a shout for help ive got a problem I could really use someone with a bit of knowledge to help me out with =)

My scenario being ive got to write a code that asks the user for input from a file (in this particular case it will be a number of folat values in .txt format), scan them into an array, and manipulate said array with a few mathematical functions, and whack it through a final calculation to give a value output to the screen.

Right now ive spent days and days trying to code the first part correctly, and its kicking my ass (Im new to any form of programming!). I could make it more basic by defining the array size, but I actually find all this quite interesting, so id rather learn the hard way :cheesy:


Anyway, without further ado, here's what ive got so far, and no, it doesnt work =P

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
    FILE *fp;
    char ch, *filename (char *buf, size_t length, FILE *f);
    long lSize;
    float *buffer;
 
int main(int argc, char *argv[])
{
#define initial_value 0.07
#define increment 0.125
    while (1)
    {
        // Input filename.
        printf("\nEnter a filename: ");
        gets(*filename);
        // Try to open the file.
        if ( (fp = fopen(filename, "r")) == NULL )
        {
            perror("\nError opening file");
            puts("\nEnter x to exit, any other to try again.");
            if ( (ch = getch()) == 'x')
                break;
        }
        else
        {
            // obtain file size.
            fseek (fp , 0 , SEEK_END);
            lSize = ftell (fp);
            rewind (fp);
            // allocate memory to contain the whole file.
            buffer = (float*)malloc(lSize);
            if (buffer == NULL) exit (EXIT_FAILURE);
                else printf("\n%d bytes of memory allocated to file...\n", lSize);
                    printf("\nSuccessful opened %s!\n", filename);
 
            // copy the file into the buffer.
 
 
            // terminate
            fclose (fp);
            free (buffer);
            puts("\nEnter x to exit, any other to continue.");
            if ( (ch = getch()) == 'x')
                break;
        }
 
    }
}
//--------------FUNCTIONS--------------
 
char *filename (char *buf, size_t length, FILE *f)
{
    char buf[40], *p;
    if (p = fgets (buf, length, f))
    {
        size_t last = strlen (buf) - 1;
        if (buf[last] == '\n') {
            buf[last] = '\0';
        }
        else {
            fscanf (f, "%*[^\n]");
            (void) fgetc (f);
        }
    }
    return p;
}

The function gives me the following errors:

19: error: cannot convert `char*(*)(char*, size_t, FILE*)' to `const char*' for argument `1' to `FILE* fopen(const char*, const char*)'
57: error: declaration of 'char buf[40]' shadows a parameter
:: === Build finished: 2 errors, 0 warnings ===

If i hash out the function, and simply replace the *filename code in line 7 with

filename[40];

it works fine!

Also, I cant tell if the code for buffer is working or not, it seems to be, but im too new to all this to tell, until i write the file into an array (which I cant do yet since I do not know how do define an array size for a file that can be of different sizes...)

The code for the array will go in the middle of the program, where ive left room for it under

// copy the file into the buffer.

Im sorry, that was a real mouthful, any help would be greatly appreciated ^^

Chris

edit: you can ignore the define's for now, theyre to be used in the calculations later on =)

The gets function takes a char pointer. When you use (*filename) you're actually passing the value stored at the address pointed to by filename, instead of passing the address stored in filename. All subsequent actions in gets using the address whose value is not a pointer will cause compiler problems. Example; say if ptr is a pointer variable to a structure, you can use either of these:

ptr->name; /* might hold a name */
(*ptr).name; /* same as above    */

Also, I think it is better formatting if you place your #define constants after the #includes.

Good luck, LamaBot

Member Avatar for iamthwee

To answer you're initial few questions, i have to use C I wish I could use C++, since it seems to be much better for dynamic memory allocation

Better no, easier perhaps...

Better no, easier perhaps...

Are you saying that it's worse, or that easier isn't better?

This pointer business has got me really confused :(

Is the general consensus that I cannot feasibly accomplish dynamiclly allocating a string size (see: my attempt at a function at the end of the program)?

Chris

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define initial_value 0.07
#define increment 0.125

int read_one_float( float* out_float, FILE *f ) ;

int main(int argc, char *argv[])
{
        FILE *file_pointer = 0;
        char ch = 0;
        char filename[40] = "" ;
        long lSize = 0;
        float *buffer = 0;
        float tmp_float = 0 ;
        int i = 0 ;
        int j = 0 ;

        // Input filename.
        printf("\nEnter a filename(max 40 chars): ");
        gets(filename);
        // Try to open the file.
        if ( (file_pointer = fopen(filename, "r")) == NULL )
        {
                perror("\nError opening file");
                return 1 ;
        }

        printf("\nSuccessful opened %s!\n", filename);
        //if we reach here file is opened successfully..

        //given it's an ascii file lets assume that there is
        //one float number per line. So total number of floats
        //in file is same as number of new lines + 1.
        // calculate the size of our buffer.
        while( EOF != (ch = fgetc(file_pointer)) )
                if( ch == '\n' )
                        lSize++ ;

        lSize++ ; //for +1

        rewind (file_pointer);
        // allocate memory to contain the whole file.
        buffer = (float*)malloc(sizeof(float)*lSize);
        if (buffer == NULL) return 1;
        else printf("\n%d bytes of memory allocated to buffer for %d entries...\n", sizeof(float)*lSize, lSize);

        // copy the file into the buffer.
        while( 0 != read_one_float( &tmp_float, file_pointer ) )
                buffer[i++] = tmp_float ;

        //can be done like this also
        //while( 0 != read_one_float( &buffer[i++], file_pointer ) )

        printf("\nnumber of entries read = %d", --i ) ;

        // terminate
        fclose (file_pointer);
        free (buffer);

        printf("\nData read from file is.") ;
        for( j = i; j >= 0; j-- )
                printf("\nbuffer[%d] = %f", i-j, buffer[i-j] ) ;

        //we have the data in the buffer
        //i contains the number of entries.

        printf("\n\n") ;

        return 0 ;
}

//--------------FUNCTIONS--------------
int read_one_float( float* out_float, FILE *f )
{
        char buf[100] = "" ;

    if (0 == fgets(buf, 100, f))
                return 0 ;

        *out_float = atof( buf ) ;

    return 1;
}

This pointer business has got me really confused :(

Is the general consensus that I cannot feasibly accomplish dynamiclly allocating a string size (see: my attempt at a function at the end of the program)?

Chris

Almost everything you can do in C++, can be done in C, so it's not true that dynamic allocation is not feasible.
One can say it's easier in C++ but it can be done in C as well.

Problem with the code I posted is that it assumes input file's format is like this:
----------------
float1
float2
...
floatN
----------------
If the file format is different the function read_one_float() needs to be adapted appropriately.
Also it would then be difficult to determine lSize.
E.g. assume this to be the format of file
----------------
float1,float2,...,floatN
----------------
OR even worse
----------------
float11,float12,float13,...,float1M
float21,float22,float23,...,float2M
...
floatN1,floatN2,floatN3,...,floatNM
----------------
In these cases one can't assume that number of '\n' is number of floats.
In all these cases using a linked list to hold the data would be better than using a float array.

In C++ you'll find lotsa nice containers to do this dynamic re-sizing of containers, that's why I said it's a lot easier (no matter what other say, that's the truth).

This pointer business has got me really confused :(

Is the general consensus that I cannot feasibly accomplish dynamiclly allocating a string size (see: my attempt at a function at the end of the program)?

Chris

It is commonly hard for a newbe to understand how pointers work. But it really isn't. Every variable has an address(s) and value(s), pointers are just variables that hold the address of another variable of the same type as the pointer. Dynamically allocating memory, you use malloc which takes the number of bytes to reserve and returns a point to this block of reserved memory. Remember that pointer of type int can only pointer to (hold the address of) a variable of type int. You cast the pointer returned by malloc to a pointer of type float; Example;

float *float_pointer;
 
float_pointer = (float *)malloc(sizeof(float));

Anyway, don't get intimidated by the concept of pointers, just read up more about them. Also, the sizeof function can be used to determine the size of a string, like this:

int i = sizeof(string);

Good luck, LamaBot

The code you provided works quite well thekashyap^^ (it compiles! thats a start!)

The problem with it seems to be that it reads a float value of say 0.7 as 0.00000, which is weird, I ran it with a file that has the values:
0.7
1.5
2.6
3.5
4.5
4.8
5
5.1
5.2
5.2

And the return is:

buffer[0] = 0.000000 buffer[1] = 1.500000[/code=C] etcetc to a final buffer of buffer[9] Id like to see a linked list demonstrated, but as for right now, that stuff is way over my head! (id be jumping forward about 200 pages in my textbook ; ;) Thanks for all the help guys^^ Chris[code=C]buffer[0] = 0.000000
buffer[1] = 1.500000[/code=C]
etcetc to a final buffer of buffer[9]

Id like to see a linked list demonstrated, but as for right now, that stuff is way over my head! (id be jumping forward about 200 pages in my textbook ; ;)

Thanks for all the help guys^^

Chris

Here we go^^ Ive edited it somewhat (the problem above is still present).

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define initial_value 0.07
#define increment 0.125
int read_one_float( float* out_float, FILE *f ) ;
int main(int argc, char *argv[])
{
    while (1)
    {
        FILE *file_pointer = 0;
        char ch = 0;
        char filename[40] = "" ;
        long lSize = 0;
        float *buffer = 0;
        float tmp_float = 0 ;
        int i = 0, j = 0 ;
        // Input filename.
        printf("\n%c %c %c %c Enter a filename %c %c %c %c : ", 4, 5, 3, 6, 6, 3, 5, 4);
        gets(filename);
 
        // Try to open the file.
        if ( (file_pointer = fopen(filename, "rb")) == NULL )
        {
                perror("\nError opening file");
                puts("\nEnter x to exit, any other to try again.");
                if ( (ch = getch()) == 'x')
                break;
        }
        else
        {
        printf("\nSuccessful opened %s!\n", filename);
        //if we reach here file is opened successfully..
        //given it's an ascii file lets assume that there is
        //one float number per line. So total number of floats
        //in file is same as number of new lines + 1.
        // calculate the size of our buffer.
            while( EOF != (ch = fgetc(file_pointer)) )
            if( ch == '\n' )
                        lSize++ ;
            lSize++ ;
            rewind (file_pointer);
 
        // allocate memory to contain the whole file.
            buffer = (float*)malloc(sizeof(float)*lSize);
            if (buffer == NULL) return 1;
            else printf("\n%d bytes of memory allocated to buffer...", sizeof(float)*lSize);
 
        // copy the file into the buffer.
            while( 0 != read_one_float( &tmp_float, file_pointer ) )
            buffer[i++] = tmp_float ;
            printf("\nNumber of entries read : %d\n\n", i-- ) ;
        // terminate
            fclose (file_pointer);
            free (buffer);
        // prints values assigned into the array.
            printf("\nData read from file is :\n") ;
            for( j = i; j >= 0; j-- )
            printf("\nbuffer[%d] = %f", i-j, buffer[i-j] ) ;
            printf("\n\n") ;
        // waits for user input to continue
            system("pause");
            system ("cls");
            puts("\nEnter x to exit, any other begin again!.");
            if ( (ch = getch()) == 'x')
            break;
        }
    }
}
//--------------FUNCTIONS--------------
 
int read_one_float( float* out_float, FILE *f )
{
        char buf[100] = "" ;
    if (0 == fgets(buf, 100, f))
        return 0 ;
        *out_float = atof( buf ) ;
    return 1;
}

The error is clearly on line 53, I just dont know what to do about it. ++i doesnt work as well :P

Hope that helps :)

Chris

Here is my output (am working on Unix):
fwk@smlcdev2(fwk_kash_src)>cat floats.txt
1.1
1.2
-1.4
6.234
2134
fwk@smlcdev2(fwk_kash_src)>cc test.c
fwk@smlcdev2(fwk_kash_src)>a.out

Enter a filename(max 40 chars): floats.txt

Successful opened floats.txt!

24 bytes of memory allocated to buffer for 6 entries...

number of entries read = 4
Data read from file is.
buffer[0] = 1.100000
buffer[1] = 1.200000
buffer[2] = -1.400000
buffer[3] = 6.234000
buffer[4] = 2134.000000

fwk@smlcdev2(fwk_kash_src)>

PS: There is nothing wrong with 1.1 being printed as 1.100000. It's only the way printf() is printing it. You can say %.2f instead of %f, it'll print only 2 digits after decimal point. Like this:
buffer[0] = 1.10
buffer[1] = 1.20
buffer[2] = -1.40
buffer[3] = 6.23
buffer[4] = 2134.00
So just print it the way you want.

Thanks for the tip on shortening the decimal places^^

The problem with the code im having tho is the first value in my (or indeed any of my) files im opening comes out to be 0.00000, even if its something like 187.3

As I said, its something to do with the statement on line 53, changing

i++

to

i--

shifts all the values 1 place down the array, so I end up with 0.00000 *then* the first value of the file being read at position

buffer[1]

, thus cutting off the last value in the file...

Any suggestions?

Chris

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.