Computing.Net > Forums > Programming > C prototype errors on compile

Computer Problems? Computing.Net has over 1,000,000 posts about all things technology related! Over 90% answered within 24 hours! Click here to start participating now! Also, be sure to check out the New User Guide.

C prototype errors on compile

Reply to Message Icon

Name: Bill Freeman
Date: May 3, 2002 at 17:09:44 Pacific
Comment:

Hello all,
I have a problem trying to compile a C program and, as a newbie to C, I am confused!
This program comes from a tutorial, "A quick introduction to the C language" by Jacob Navia (from the documentation of his Lcc-win32 compiler).
Here is the program (with apologies for the size of this post);

#include // for malloc mem mananger
#include // for FILE str
#include // for firstfind/findnext
#include // for memcpy

/* This change in the p50 program development is to test
that memory is available when requested and to exit with
a message if not. this uses a memory allocation fn (p88).
also it removes the _finddata_t str. in our Stream str.
which is not used (we thought that we would use itz0 */


Define global variables and declare/define objects needed
by the program


// define structure and typedef(define our own) our CHARS
// which have two variables; value and frequency (count)
// for the characters we will read from a file
typedef struct tagChars {
int CharacterValue; // the ASCII value of the char
int Frequency; // how many seen so far
} CHARS;

// Declare array of 256 frequencies, which are 256
// structures of tagChar type, containing each
// characters value (ID) and the no. of occurences of it
CHARS Frequencies[256];

// define our own STREAM structure to hold all
// info needed to use the findfirst & find next functions
// , name of the file &
// a FILE pointer to the file (the first file found)
typedef struct tagStream {
char *Name; // input name with possible * & ? in
long handle;
FILE *file; // an open file
} STREAM;

-------------------------
This is the start of the individual modules
-----------------------*/

// check input args: have we got a file name? Module 1
// can it be opened?
// is it empty? does it exist?
// note that now we use stream not file and call find
// first not fopen
STREAM *checkargs(int argc, char *argv[])
{
// initialise
STREAM *infile = NULL;
long findfirstResult;
struct _finddata_t fd;

// check if a file is given as an arg. in cmd line
if (argc \n");
}
else {

// use the findfirst fn to examine the file arg.
// and return its unique no. to findfirstResult var.
// call the firstfind fn with name & info buffer
findfirstResult = _findfirst(argv[1], &fd);

// if the file arg isn't given, tell the user
// this tests the result of findfirst
if (findfirstResult Name = argv[1]; // name of our file stream

// copy the fd _finddata_t str into our new stream
// str

// note the first arg of this call; it's the address within the infile
// str. of the FIndData memberl We take the address with the & operator.
// Since we are using a pointer, we have to dereference a pointer, i.e.
// with -> not . Note that the & operator is used with the fd variable
// to obtain a pointer from a structure member.
// memcpy(&infile->FindData,
// &fd,
// sizeof(struct _finddata_t));

// use fopen to set the file pointer of our str
// to the name of the file read (which is in our
// new str
infile->file = fopen(fd.name, "rb");

// this uses the _finddata_t fn's unique value
// result to initialise the handle part of our
// new stream str.
infile->handle = findfirstResult;
}
return infile;
}


// collect all initialisations here Module 2
void Initialise(void) // note spelling- not yankee
{
// assign each CHaracterValue field a no from 0 to 256
for (int i = 0; i file);
while (c != EOF) {
count++; // add 1 to count for each char read
if (c >= ' ') // remove r and newline chars
Frequencies[c].Frequency++; /* update array,
add 1 to
address of
the char read into c */
c = fgetc(instream->file); // auto moves to next char
}
return count;
}


// display output fn Module 4
void DisplayOutput(CHARS *Frequencies)
{
for ( int count=0; counthandle, &fd);

if (findnextResult FindData,
// &fd,
// sizeof(struct _finddata_t));
result->handle = stream->handle;
result->file = fopen(fd.name, "rb");
result->Name = stream->Name;
return result;
}

// Module 6
// compare function- needed to tell qsort if the
// next record is larger, smaller or equal to the
// previous one. called by the qsort fn
int compare(const void *arg1, const void *arg2)
{
CHARS *Arg1 = (CHARS *)arg1; /* cast our args into
pointers to CHARS */
CHARS *Arg2 = (CHARS *)arg2;

// compare both integers(chars)
return ( Arg2->Frequency - Arg1->Frequency );
}


// Module 7
// This is to test to see if more memory is available
void *xmalloc(unsigned int size)
{
void *result = malloc(size);

if (result == NULL) {
fprintf(stderr,
"No more memory left!\nProcessing stops\n" );
exit (1);
}
return result;
}

--------------------------
This is the start of our new, shortned and simplified
main function
-------------------------*/

int main( int argc, char *argv[] )
{
// declare local variables
int count=0; // chars read to get total; zeroed in fn,
// but this variable is used again just
// below.

STREAM *infile = checkargs(argc, argv);

// if checkargs returns an error, exit main
if (infile == NULL) {
return 1;
}
// call initialise fn
Initialise();

/* call ProcessFile fn and put its result into
the count variable. the do loop means that the
loop will aloways run at least once */
do {
count += ProcessStream(infile, Frequencies);

// close the opened file
fclose(infile->file);
infile = GetNext(infile);
} while (infile !=0);

// print no of chars; from count variable
printf("%d chars in file\n", count);

// sort array with qsort
qsort(Frequencies, 256, sizeof(CHARS), compare);

// print out array
DisplayOutput(Frequencies);
return 0;
}

When I try to compile this I get the following errors;

Warning p88.c : 78 Missing prototype for xmalloc
Error p88.c: 78 Operands of = have illegal types 'pointer to struct tagStream' and 'int'
Warning p88.c: 165 Missing prototype for xmalloc
Error p88.c: 165 Operands of = have illegal types 'pointer to struct tagStream' and 'int'
Warning p88.c: 195 Declaration of 'xmalloc' does not match previous declaration at c;\my documents\programming\C\lcc\projects\p88.c 78
2 errors, 3 warnings.

I keep having the feeling that I should be able to work this out, but my brain refuses to co-operate.
I have previously found some typos in this tutorial that I have been able to correct, but not this problem.
I hope that someone can assist me, as this program is an on-going one, developed in this tutorial in many ways, to illustrate program improvements. Of course these errors put a stop to continuing!

Regards,
Bill Freeman



Sponsored Link
Ads by Google

Response Number 1
Name: Jeff
Date: May 4, 2002 at 20:51:58 Pacific
Reply:

Actually, it's great you gave as much info as possible. It's difficult when there's too little. However, after copying to a text file, it's hard to locate the line numbers the compiler squawks about. That would be most helpful.

The first thing I noticed, was that the pointer to the STREAM structure, infile, is initialised to NULL (zero), which by itself is good. The code then tries to use it, without pointing it to anywhere. Since a pointer is ultimately intended to "point" to something's memory address (a STREAM struct in this case), it must be valid, or the computer can crash.

It's good practice to init pointers to null, so they can be checked for validity, before trying to use them. For example...

int *pInt = NULL; //points to memory
//0x00000000, which is
//invalid

pInt = &iValue; //assign address of iValue

if (pInt != NULL) ... //check if valid
//before using

In your code, infile never gets assigned the address of the STREAM structure. So, when you use it in the line...

infile->file = fopen(fd.name, "rb");

...there's nothing there. The compiler knows this, because there was no code to assign the pointer, such as like this:

infile = &STREAM;

You'll need to add that somewhere. My guess is that the code inside the else clause's curly braces, should look like this:

infile = &STREAM; //point to global STREAM
infile->Name = argv[1];
infile->file = fopen(fd.name, "rb");
infile->handle = findfirstResult;

Then the "checkargs" function should work. The compiler might then get stuck somewhere further on, but cross that bridge when you get to it.


0

Response Number 2
Name: Bill Freeman
Date: May 5, 2002 at 00:12:32 Pacific
Reply:

Hello Jeff,

Thanks very much for your reply. Being new to C any help is great. I will study your reply and will post any further errors.

As to the line numbers; they are;
line 78:
"infile = xmalloc(sizeof(STREAM));"
this is after the line;
"// allocate mem to our STREAM....."
line 165:
"result = xmalloc(sizeof(STREAM));"
this is after the line;
"return NULL"
line 195:
"void *xmalloc(unsigned int size)"
this is after the line;
"// this is to test to see..."

The lcc compiler runs in DOS ( I think it is based on gcc) and I don't know how to get the line numbers to print out in DOS!!

Regards,
Bill


0

Response Number 3
Name: Jeff
Date: May 5, 2002 at 10:22:27 Pacific
Reply:

That makes things very clear, thanks. The solution's very simple, but please tolerate my explanation first :)

Pointers are really just unsigned integers that contain the numeric address to something in memory. However, the compiler treats pointers (anything declared with a * in front of it) differently than regular integers. It's not enough to know something's address; the compiler also needs to know how much data extends from that starting address. Hence, a pointer implies size too.

In C/C++, pointers are typically cast to tell the compiler to believe that the size/type of data pointed to, is different than previously stated. A void pointer specifically points to nothing in particular. The compiler won't simply allow one to blast values into memory (to who knows what), so you must cast (unless you're assigning to another void pointer)...

void *pVoid = NULL; //void pointer
int *pInt = NULL; //null pointer to int
int iVal = 7;

pVoid = &iVal; //ILLEGAL! How much memory?
pInt = pVoid; //Illegal for same reason

//This will work, since we'll cast to a
//void pointer (says to ignore size/type)
pVoid = (void*) &iVal; //No error

//This too will work, since we cast to a
//pointer to an int. The compiler knows
//what an int is, and that it's 4 bytes
pInt = (int*) pVoid; //No error

Enough of that. Line 78 should be:

infile = (STREAM*) xmalloc(sizeof(STREAM));

The snippet you posted doesn't go far enough to see the later error, but just cast it similarly, to whatever pointer type you're trying to assign to. The compiler error makes me think you need to cast the pointer to an int, to a pointer to a STREAM. Try this:

result = (STREAM*) xmalloc(sizeof(STREAM));

However, I think there's another problem, in that you have more than one definition of xmalloc(), possibly with one returning a pointer to an int, rather than the usual pointer to void. You can comment out the extra one, so the compiler doesn't get confused.


0

Response Number 4
Name: Jeff
Date: May 5, 2002 at 10:47:48 Pacific
Reply:

One bit of overbearingness when I posted my explanation: most compilers DO allow assigning any pointer, to a void pointer. That's known as an implicit conversion, so you don't have to cast (though it's fine to do so). But you most definitely do have to cast when going FROM a void pointer, to something else (the cause of the errors).

Many years of avoiding void pointers in C++, has definitely made me jaded.


0

Response Number 5
Name: Bill Freeman
Date: May 5, 2002 at 20:27:47 Pacific
Reply:

Hello Jeff,
Good work Jeff, that starts to make sense to me. I will change line 78 to what you suggest and look for the second declaration/definition of xmalloc as soon as I can and post back.
Perhaps Module 7 (line 195) should read;
void *xmalloc(sizeof(STREAM))??
Which one is a declaration and which one is a definition?
C is a difficult language to learn (Qbasic was much easier!), but I am picking it up slowly.
Thanks for your help.

Regards,
Bill


0

Related Posts

See More



Response Number 6
Name: Jeff
Date: May 6, 2002 at 11:32:40 Pacific
Reply:

The declaration/definition thing was the most confusing thing I remember, when transitioning to C from the original BASIC (yes, back in the '70s). Headers can be a pain, but well worth it.

Declaration is any line in C/C++, that describes what kind of thing a name (identifier) represents. That includes functions, structs, local vars, etc. A declaration by itself, does not include any use of the "=" sign, since that means the named thing is then being used, not just described. However, variables and arrays are commonly declared AND defined (initialised) in the same line...

int i; //declaration
i = 7; //definition
int k = 7; //declaration and definition

...but functions are not...

int MyFunc(int i); //declaration
int MyFunc(int i) //defined on new line
{ //notice curly braces
return i + 2;
}

According to ANSI C standards, all function definitions (I prefer the term implementation for functions) must be preceded by a declaration of it (AKA a prototype). This is partly to coerce you to group declarations into a header file, which are typically #included just before the implementations in a .c file. It's easy to cheat by putting both in the .c file, and this is common when writing how-to-code articles. I makes it easier to explain and follow the code.

Obviously, most compilers, like yours, allow functions to be implemented (all code written-out), without declaring them first. You merely skipped declaring xmalloc(), and got off with just a warning.

A definition of named data (unlike functions which contain active code), typically occurs the first time a value is assigned to it (using "="). Thus with

int i = 7;

integer i is defined as having a value of 7, whereas with

int i;

integer i is undefined (uninitialised), so who knows what value it has. Similary with arrays:

char string[]; //declared, but undefined
char string[] = "text"; //defined too

Function declarations have no curly braces, just a prototype, ending with a semi-colon. Its definition/implementation begins with the same prototype, but adds curly braces, into which goes the body of its code.

Function declarations seem redundant, but you'll find headers (containing declarations) are a great way to describe the contents of larger source/implementation files. Headers are also used to describe the contents of pre-compiled static libraries (.lib and .obj files), as well as dynamic libraries (.dll files in Windows parlance). The BASICs can't do that, and VB even had to add something known as a TypeLibrary to substitute for C-style headers.

Sorry for rambling on; I guess I miss my teaching years.


0

Response Number 7
Name: Bill Freeman
Date: May 7, 2002 at 00:37:42 Pacific
Reply:

Hello Jeff,

Please feel free to ramble on anytime!
Thanks for your explanation, which I found
a great help. You know, it didn't even occur to me that I did not declare xmalloc. Hmmm.. I have a lot to learn!
As yet I haven't had time to try your suggestion for line 78, as I only have a hour or two spare a day. (Not much compared to what I need to do!).
In the next few days I will try the line 78 changes, declare xmalloc and experiment with line 195; perhaps changing it to;
"void *xmalloc(sizeof(STEAM))" and see what it does.
I will post the results and, once again, thanks.

Regards,
Bill


0

Response Number 8
Name: Jeff
Date: May 8, 2002 at 09:14:00 Pacific
Reply:

If the post gets too old, feel free to email me at my posted address. I love to ramble on about programming :-)


0

Response Number 9
Name: Bill Freeman
Date: May 9, 2002 at 00:24:04 Pacific
Reply:

Hello Jeff,

Thanks Jeff, I will E-Mail if necessary.
I did use your suggestion to re-cast line 78 and 165 as;
"infile = (STREAM*)xmalloc(sizeof(STREAM));"
and it worked perfectly!
This removed the errors about illegal types on opposite sides of the '='.
Then I declared xmalloc in the global section of my program and this eliminated the warnings and also the line 195 warning;
"Warning p88.c 195 Declaration of 'xmalloc' does not match previous declaration at c:\my documents\programming\c++\projects p88.c 78".
I found this line confusing and now see that the compiler error messages are not a concise guide to the problem, but need interpretation.
I have moved on with this tutorial and now have a program that can handle the path names and works perfectly.
There is still about 120 pages of this tutorial to go and after that I will be looking for a new one to follow. This tutorial seems to be to be better than the books that I have, so maybe you can advise on where to find more internet C tutorials.
Many thanks for your help.

Regards,
Bill


0

Response Number 10
Name: Jeff
Date: May 9, 2002 at 10:48:13 Pacific
Reply:

Alas, I once had several tutorials on my programming website, but I no longer pay for the web space. I specifically wrote them because I found so few good books/tutorials out there. Most were beyond where you currently are (templates, classes, STL, super-high-efficiency, etc.), but I did nearly finish "C++ For VBers", which you might find helpful.

It's a few MBs, but never became a book because Microsoft replaced COM-based VB with VB.NET just as I was finishing it. Some fellow programmers found it useful, so maybe you will too. It's only slightly VB-oriented (I didn't want to limit my audience), so it mostly focuses on the common C subset shared by both C and C++, as well as C++'s more advanced offerings. Begins with the rudiments, and lots on pointers.

I'll zip it and send it to you, though realise some parts are not quite finished. Beyond that, I strongly, strongly recommend what many better programmers I know, consider the best C/C++ reference, "C++: The Complete Reference" by Herbert Schildt. He's very clear and concise, and not limited to C as with the classic but still excellent "C Programming" by Kernighan and Ritchie (the inventors of C). Still others swear by "C++ Primer" by Stanley Lipman, and I like him, but I find his code examples hard to follow.

Schildt's reference can be found for $24 new, and works as both tutorial and handy reference (the others are mostly how-tos), and hence useful for years to come. He also has tutorials, such as "C++ from the Ground Up" and "Teach Yourself C" for around $15, but I feel a good reference is a must. With that by your side, you can work your way through many web and other tutorials, and fill in the holes they leave.

Although pure C is a good place to start with the C-based languages, try to keep an open mind towards C++ (they share the C part almost identically). That will make eventual expansion to C++ much easier (C++ is mostly an extension of C).


0

Sponsored Link
Ads by Google
Reply to Message Icon






Post Locked

This post is quite old and has been locked from receiving new replies. Please create a new posting instead.


Go to Programming Forum Home


Sponsored links

Ads by Google


Results for: C prototype errors on compile

C++ Socket library? www.computing.net/answers/programming/c-socket-library/13440.html

Error during compilation www.computing.net/answers/programming/error-during-compilation/10217.html

C language error www.computing.net/answers/programming/c-language-error/3595.html