Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Apr 11th, 2006, 12:26 AM   #11
The Dark
Expert Programmer
 
Join Date: Jun 2005
Posts: 893
Rep Power: 4 The Dark is on a distinguished road
Quote:
Originally Posted by grumpy
The question was about why the code didn't compile. Getting the code working correctly (eg eliminating memory leaks) is a separate issue. Albeit a pretty important one.
Yes, but making "isa" as an array of pointers would make it compile. Then you wouldn't need to change the function calls and dereference the return values.
The Dark is offline   Reply With Quote
Old Apr 11th, 2006, 4:44 AM   #12
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,260
Rep Power: 5 grumpy will become famous soon enough
Quote:
Originally Posted by The Dark
Yes, but making "isa" as an array of pointers would make it compile. Then you wouldn't need to change the function calls and dereference the return values.
Sure. My minor objection to your previous post was your asking if it should be an array of pointers. There is no "should" about it; the code and other information provided in this thread suggested the caller wanted to work with an array of structs, not an array of pointer. Without changing data types (eg making isa an array of pointers), it is necessary to convert isa[k] to a pointer (by taking its address) to pass it as an argument, and to dereference the pointer returned by the function to assign the value to the array element.

If you want to push it, we could also make isa an array of size_t instead of an array of pointers, viz;
#include <stdlib.h>

int main()
{
     size_t isa[30];

     /*  declare and initialise opcode, args, type */

     /*  and later with a value of k  ..... */
     
     isa[k] = (size_t) insertinstrlist((instr *)(isa + k), opcode, args, type);
}
Apart from the casts this is exactly equivalent to having isa as an array of pointers, and would work identically (I'll leave it as an exercise to work out why, as the explanation will be slightly enlightening to people who work through it). But that doesn't mean that one should use such an approach.... in fact, I would quietly shoot people who attempted something like this in production code without a VERY good reason.
grumpy is offline   Reply With Quote
Old Apr 11th, 2006, 6:03 AM   #13
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Quote:
Originally Posted by grumpy
in fact, I would quietly shoot people who attempted something like this in production code without a VERY good reason.
Hmm I thought you were a peaceful person and guns were forbidden in Australia...
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Apr 11th, 2006, 6:05 AM   #14
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,260
Rep Power: 5 grumpy will become famous soon enough
Generally, I am a peaceful person. But some things wind me up.

And there are ways to shoot people without a gun ......
grumpy is offline   Reply With Quote
Old Apr 11th, 2006, 9:33 AM   #15
deanosrs
Programmer
 
deanosrs's Avatar
 
Join Date: Apr 2006
Location: Bristol, UK
Posts: 31
Rep Power: 0 deanosrs is on a distinguished road
Send a message via MSN to deanosrs
Really grateful for all the help you guys have given me, am much more confident with pointers now. Just a couple more q's...

You've got me a little worried with talk of memory leaks! After I've initialised the isa array and entered all the values into it, and this bit of code works in that it prints out what I'd expect it to:

	char opcode[5];
	strcpy(opcode, isa[13].opcode);
	printf("%s", opcode);

Does that rule out the possibility of a memory leak?

Also, would be very grateful if someone could explain what is meant by the term "cast". I see it everywhere and it's kind of assumed in every tutorial I read that I'll know what it means so feel a bit stupid asking that, but still...!

Thanks again.
deanosrs is offline   Reply With Quote
Old Apr 11th, 2006, 9:49 AM   #16
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Quote:
Originally Posted by deanosrs
You've got me a little worried with talk of memory leaks! After I've initialised the isa array and entered all the values into it, and this bit of code works in that it prints out what I'd expect it to:

	char opcode[5];
	strcpy(opcode, isa[13].opcode);
	printf("%s", opcode);

Does that rule out the possibility of a memory leak?
You're safe with that, char opcode[5] is an array which gets cleaned up when it gets out of scope. Make sure you're not trying to write out of your memory though (isa[13].opcode being larger than 1 char).

Quote:
Originally Posted by deanosrs
Also, would be very grateful if someone could explain what is meant by the term "cast". I see it everywhere and it's kind of assumed in every tutorial I read that I'll know what it means so feel a bit stupid asking that, but still...!
Casting is changing from one type to another. If I have an int and want it to be a char then I would do:
int i = 65;
char c;
c = (char) i;
c will now represent an 'A' because 'A' in ASCII is 65.
You can cast all kind of types, in C++ you can do more casts, like static_cas, const_cast, dynamic_cast and reinterpret_cast.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Apr 11th, 2006, 11:05 AM   #17
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
Let me expand just a tad, to avoid a misinterpretation: the cast doesn't change the type of the variable it's applied to, it forces that variable to be interpreted as another type, if possible. In Ruben's example, i remains an int. Its value is demoted to char and assigned to c on the fly, so to speak.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Apr 11th, 2006, 11:07 AM   #18
deanosrs
Programmer
 
deanosrs's Avatar
 
Join Date: Apr 2006
Location: Bristol, UK
Posts: 31
Rep Power: 0 deanosrs is on a distinguished road
Send a message via MSN to deanosrs
Ok thanks, I always like to make sure I understand what's going wrong in programs when I get stuck as well as just getting them to work, so I don't come pestering you guys again with the same problem!

Thanks again for all the help.
deanosrs is offline   Reply With Quote
Old Apr 11th, 2006, 8:04 PM   #19
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,260
Rep Power: 5 grumpy will become famous soon enough
Quote:
Originally Posted by deanosrs
After I've initialised the isa array and entered all the values into it, and this bit of code works in that it prints out what I'd expect it to:

	char opcode[5];
	strcpy(opcode, isa[13].opcode);
	printf("%s", opcode);

Does that rule out the possibility of a memory leak?
This code neither causes a memory leak nor gives assurances that some other code has not caused a leak. If [for sake of discussion] strlen(isa[13].opcode) was greater than 4 (i.e. none of the 5 bytes in isa[13].opcode was zero) then the strcpy() call would yield undefined behaviour as it would copy more than 5 bytes, despite the fact that opcode and isa[13].opcode are arrays of length 5. That is not a memory leak, but it is erroneous behaviour. And successfully printing out opcode afterwards is not enough to be sure that hasn't happened.

A memory leak is what happens if we do this;
    some_type *x = malloc(some_size);

     // later lose track of x and never delete it
For example;
#include <stdlib.h>

int *Allocate()
{
     return malloc(2*sizeof(int));
}

int main()
{
    int i;
    for (i = 0; i < 5; ++i)
         Allocate();

    /* we no longer keep track of memory allocated by Allocate() so cannot
          release it.   That memory is said to be leaked */
}

Quote:
Originally Posted by deanosrs
Also, would be very grateful if someone could explain what is meant by the term "cast". I see it everywhere and it's kind of assumed in every tutorial I read that I'll know what it means so feel a bit stupid asking that, but still...!
nnxion has given the common interpretation of casting as a conversion. It is often used as that but, as Dawei said, it's real purpose is to tell the compiler not to complain when code treats a variable of type X as if it is actually of type Y.

It may seem like I'm talking about conversions, not casting, here. But bear with it.

In practice, possible conversions from one type to another fall into three categories;
1) Conversions that are always possible. These are specified in the C standard as "implicit conversions". For example, the following code yields no complaints from a self-respecting compiler;
void SomeFunction(int);

main()
{
   char x =65;   /* Letter A in ASCII character set */
   int y;
   y = x;    /* implicit conversion of x to int */
   SomeFunction(x);   /* implicit conversion of x to int */

2) Conversions that are sometimes possible. These are usually flagged as conversions that lose precision (eg converting from a larger type to a smaller type). An example would be;
void SomeFunction(char);

main()
{
   int x = 165;  /* value bigger than can be held in a char */
   char y;
   x = y;    /* loss of precision here */
   SomeFunction(x);   /* loss of precision here */
In practice, these are not errors as far as the C standard are concerned. However, in practice, compilers often give warnings (and still allow the code to compile) as the operations are suspicious. The way to stop the compiler complaining is to use a cast;
void SomeFunction(char);

main()
{
   int x = 165;  /* value bigger than can be held in a char */
   char y;
   x = (char)y;    /* loss of precision here */
   SomeFunction((char)x);   /* loss of precision here */
This does not change the end result or eliminate any potential errors in the code, but does stop the compiler complaining about them. Ideally, one should also ensure the conversion is valid before stopping the compiler complaining;
void SomeFunction(char);

main()
{
   int x = 165;  /* value bigger than can be held in a char */
   char y;
   if (x > -128 && x < 127)   /* check valid range of char */
   {
       x = (char)y;  
       SomeFunction((char)x);
   }
   else
      do_something_else();

3) Conversions that are, technically, disallowed by the standard but we want to do them anyway.
void SomeFunction(long *);

int main()
{
     short *px;   
     char a[2], *pa; 
     pa = a;
     px = pa;                 /*  Error.  Code will not be allowed to compile */
     *px = 100;
     SomeFunction(pa);   /*  Error.  Code will not be allowed to compile */
}
Technically, the code above is valid (as a value of 100 can be stored in a short), but the C standard disallows conversions between most pointer types, so self-respecting compilers complain bitterly and refuse to compile this code. But casts come to our rescue, and tell the compiler to shut up.
void SomeFunction(short *);

int main()
{
     short *px;   
     char a[2], *pa; 
     pa = a;
     px = (short *)pa;
     *px = 100;
     SomeFunction((short *)pa);
}
The danger with this type of thing is that it is a VERY good way to introduce undefined behaviour, with a small change of variable types. For example, if we use shorts instead of longs and a bigger value, the above example turns into (without casts);
void SomeFunction(long *);

int main()
{
     long *px;   
     char a[2], *pa; 
     pa = a;
     px = pa;                 /*  Error.  Code will not be allowed to compile */
     *px = 70000;
     SomeFunction(pa);   /*  Error.  Code will not be allowed to compile */
}
which is the compiler doing us a service. A long is typically 4 or more bytes, so treating an array of two chars as a long yields undefined behaviour.
void SomeFunction(long *);

int main()
{
     long *px;   
     char a[2], *pa; 
     pa = a;
     px = (long *)pa;
     *px = 70000;          /*  Undefined behaviour here, as 70000 cannot be stored in two bytes */
     SomeFunction((long *)pa);
}
In this case, the casts have not changed the conversions done, but they have told the compiler not to complain about them. And when we try to inject a value of 70000 into an array of two bytes, we get undefined behaviour. Symptoms of undefined behaviour can be anything from nothing (i.e. no visible symptoms) through to an unexplained program crash.

Basic message: just because we can use a cast to beat the compiler into submission and force it to do a conversion, doesn't mean we should. As a general rule, if a compiler complains, it is doing you a service. Just telling it to shut up, and not fixing the underlying problem, is asking for trouble.

Yes, casts can be (and, in some cases, have to be) used for conversion. But you - the programmer - need to be sure the conversion is actually valid as their real purpose is to stop the compiler complaining about things it wouldn't normally allow.
grumpy is offline   Reply With Quote
Old Apr 12th, 2006, 3:53 AM   #20
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Very nicely explained grumpy.

Quote:
Originally Posted by grumpy
Symptoms of undefined behaviour can be anything from nothing (i.e. no visible symptoms) through to an unexplained program crash.
I thought you once said that undefined behaviour could be even worse, like wiping the hard disk. on That Other Forum you had a nice 'article' about sorts of behaviours, maybe you'd like to put that up in David's Contributor's Corner™ as well.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 2:28 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC