Lessons Learned && quiz (C/C++ programming)

Had your computer crash on you, or a website shows wrong, or your printer went dead on you? Come on in...

Moderator: Crew

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Tue Sep 25, 2007 19:50

Maz wrote:Okay, I'll give you hints.

1. for the vector puzzle... Look at the order of operations in loop... ;)

2. For the 'return pointer to a variable' puzzle, what is the scope of the? What happens when program leaves the scope of the i?
To be more accurate:
1. for the vector puzzle... Look at the order of operations in loop condition... ;)
2. For the 'return pointer to a variable' puzzle, what is the scope of the i? What happens when program leaves the scope of the i?

User avatar
Pager
Winner of CWF review contest!
Posts: 1249
Joined: Mon May 01, 2006 15:54
Location: Berlin, Ontario

Post by Pager » Thu Sep 27, 2007 17:52

Okay Maz, I've been brushing up hardcore on my programming...so here we go...
For The vector loop question:

Correct me if I'm wrong here...the condition is saying to keep only if vectorOfInts does not equal 5 AND the size is greater than i?

If that is so, it would mean that the loop would only stop if these two are satisified. But what happens when you get to the end of i, and there are no more vectors, but it has never been equal to 5?

I would suggest putting an || instead of the &&.


As for the pointer question:

At this point, the only thing I can think of is the value of i only exists within the scope of this function. So when you return the pointer value of i, you're only returning the address back to the program. However, when the function terminates, you have an address with no value stored.

BTW, Maz, I really appreciate these examples, even if I am no where near being correct. This will really help when I write the C++ test at work in a couple of weeks.
CWF - Safer than Crack, Twice as Addicting

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Thu Sep 27, 2007 22:28

First is wrong. Second is absolutely correct :) Answer to no 1. will come a bit later ;)

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Mon Dec 24, 2007 0:47

I'm sorry for the delay.. I forgot this thread :)

Anyways, to speculate Pager's answer:
The program will stay in the (for) loop as long as the condition is true. Now, when we look at the condition with AND operation (&&), the condition is true as long as both checked things are true. Immediately when one of the conditions are false, the result of AND will be false, and program will leave the loop. So we are safe in that sence, because program will leave loop instantly, if value in vector is 5, or if we encounter the end of the vector. (i is greater than size of the vector).

Problem is the order of the checks:
for(i=0;vectorOfInts!=5&&(int)vectorOfInts.size()>i;i++)


At first we have check vectorOfInts!=5.
At this phase the program checks if 5th. value in vector is 5. After that we check (int)vectorOfInts.size()>i if we are still reading valid values. However, at that phase - if we have reached the end of the vector at previous loop - it's too late to do this check. We have already read the value which is outside of the vector when we do the first check. This is surely an access violation, which may at worst case cause a crash.

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Wed Jan 23, 2008 21:27

Well, once again it's a time to give you small puzzle :)

This is actually not an error I have done, but an error I have fixed zillin times - thx to my co-workers..

Now, let's assume we have a machine running some SW which is listening for incoming data. When data arrives, it will be copied in certain memory location pointed by pointer *loc.

Then we cast this loc pointer into a struct pointer, in order to use the data.

I know this sounds confusing, but actually it is not :D

So what we must do, is to make sure the sent data "matches" the struct we use.

Let's say we have struct

Code: Select all

struct foo {
char param1;
char param2;
char param3;
int param4;
char param5;
};
Now, char is 8 bit long value, so we send first char values making them 8 bit long. Let's assume we wish 1. param be 0xAA, second 0xBB, and third 0xCC.

Then we have int, which is 32 bit wide. Lets say we want int to be 0xDDDDDDDD.
And then one more char, which is again 8bit wide. Lets say we want it to be 0xEE.

Now, if we send data AABBCCDDDDDDDDEE and do as I said, (code below) something fails... What's wrong?

Code: Select all

typedef struct foo {
char param1;
char param2;
char param3;
int param4;
char param5;
}foo;

foo* fill_struct( foo *filled_struct)
{
     void *received_data=NULL;
     receivesentdata(received_data);
     if(received_data==NULL)
     {
           printf('error, no data received');
           filled_struct=NULL;
           return (foo *)NULL;;
      }
      memcpy((void *)filled_struct,(void *)received_data, sizeof(foo));
      return filled_struct;
}
(I wrote the code without checking it's correctness, so there may be some bugs. But the question is, what is wrong with sending AABBCCDDDDDDDDEE and copying it blindly in the struct?

User avatar
Zyx
Pretender to the throne
Posts: 1854
Joined: Wed Mar 29, 2006 20:48
Location: Helsinki
Contact:

Post by Zyx » Thu Jan 24, 2008 14:54

Well, one thing that comes to my mind is assuming int is indeed 32-bit.
Do you has what it takes to join the Homestarmy? The guts? The determination? The five bucks? Join today!

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Thu Jan 24, 2008 16:43

Int is 32 bit. That's in ISO/ANSI standard... There's much more serious issue than non standard compilers. ;)

good point though

User avatar
Zyx
Pretender to the throne
Posts: 1854
Joined: Wed Mar 29, 2006 20:48
Location: Helsinki
Contact:

Post by Zyx » Thu Jan 24, 2008 19:39

I was quite sure it wasn't that because you mentioned int being 32-bit. But, generally speaking, doesn't C's Int depend on hardware (CPU)? On 32-bit system it is, well, 32-bit, but in 16-bit systems like DOS and some embedded platforms it's 16 bits?

I get really easily confused with pointers and stuff in C, so I really can't offer any other guess. Or...

Is it that the pointer for *received_data is initialized as NULL, but it's contents are not? (So that in many cases the IF-statement isn't null eventhough no data was received?)
Do you has what it takes to join the Homestarmy? The guts? The determination? The five bucks? Join today!

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Fri Jan 25, 2008 12:54

C int is 32 bit. If the implementation does not support that, then it is not standard C. However, I have not (yet) encountered system not supporting 32 bit integers, even though I am working with sort of embedded systems. That does not mean that those do not exist though :)

But in this puzzle, we can safely assume int is 32 bit wide :)

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Fri Jan 25, 2008 18:34

I will give you a hint:
This problem could be avoided by changing the order of the struct members, or by using some pragmas. However pragmas are often somewhat compiler specific, so I rather choose the first option. (I mainly write SW which should be portable)

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Sun Jan 27, 2008 10:33

Okay, second and last hint, the most common form of the pragma is something like
#pragma pack(1)

User avatar
Zyx
Pretender to the throne
Posts: 1854
Joined: Wed Mar 29, 2006 20:48
Location: Helsinki
Contact:

Post by Zyx » Sun Jan 27, 2008 12:42

One of the reasons I use "scripting" languages is just that I don't want to know anything about memory addressing, pointers or compile-time settings.

So, the mistake has something to do with assuming a wrong size for some types? I've no idea why that happens or where.
Do you has what it takes to join the Homestarmy? The guts? The determination? The five bucks? Join today!

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Sun Jan 27, 2008 13:53

That's exactly why I prefer C over scripting langs. I want to place each bit in memory by myself :D

Allright. I'll spill it out then.

Reason is that with most of the compilers and architectures, we need to have a whole 32 bit memory block for storing a 32 bit value. If we now look at our structure, (let's see if I can use some ascii graphics to explain)


memory:

Code: Select all

|xxxxxxxx|xxxxxxxx|xxxxxxxx|
Now, we store 3 first 8 bit wide parameters:

Code: Select all

|AABBCCxx|xxxxxxxx|xxxxxxxx|
As we see, in the first 32 bit wide block is still 8 unused bits. But because next parameter is int (32 bit wide), compiler want's to place it to begin from empty 32 bit block. Most of the compilers do so called 'padding' and leave the last 8 bits in first block unused.

Code: Select all

|AABBCCxx|DDDDDDDD|xxxxxxxx|
and then the last char is stored in the beginning of the third block:

Code: Select all

|AABBCCxx|DDDDDDDD|EExxxxxx|
This is how struct is excpected to be filled, if we use default settings (no pragmas) (and as a side note, last 3 Bytes Eg. 24 bits are also allocated for the struct even though thy're not used).

Now, when we do our memcpy in the example, our memory is

Code: Select all

|AABBCCDD|DDDDDDEE|xxxxxxxx|
First 3 parameters appear to be correct, but the integer is now
DDDDDDEE instead of DDDDDDDD. And last character is ... well, undefined.

So we can basically either send the parameters as
char p1
char p2
char p3
char unusedjunk
int p4
char p5

or change the order of parameters to be
char p1
char p2
char p3
char p5
int p4

(or use the pragma to avoid padding).

But anyways, Zyx was on the right tracks, and with a lil bit of googling the pb would have been solved ;)

User avatar
Zyx
Pretender to the throne
Posts: 1854
Joined: Wed Mar 29, 2006 20:48
Location: Helsinki
Contact:

Post by Zyx » Wed Feb 06, 2008 18:19

Okay, next up, fun with pathological C declarations.

What the heck is the following?

Code: Select all

int (*(*vtable)[])();
Do you has what it takes to join the Homestarmy? The guts? The determination? The five bucks? Join today!

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Thu Feb 07, 2008 8:36

It looks a bit like an array of function pointers. But I am not 100% sure. I hate to put those up in that a cryptic way. Usually I do typedef's for func pointers, and then the array using the typedef.

Perhaps that mumbojumbo forms a pointer to array of function pointers.

Functions are returning int, and having no parameters?
Let me see.. It would be

//function ptr
typedef int (*vtable)();
//array
vtable *foo[];

mm.. somehow it does not look correct. I dope you're not that nasty that you gave us pointer to function which is returning a function pointer. That would be just too cruel. Heck, I should try to see those formatting rules again.

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Thu Feb 07, 2008 9:21

No. array of func ptrs would be
int (*vtable[])()
An array of pointers to function pointers to functions returning ints would be
int (*(*vtable[]))()
so
int (*(*vtable)[])() is perhaps a pointer to array of pointers to function pointers to functions returning ints

User avatar
Zyx
Pretender to the throne
Posts: 1854
Joined: Wed Mar 29, 2006 20:48
Location: Helsinki
Contact:

Post by Zyx » Thu Feb 07, 2008 9:43

Do you has what it takes to join the Homestarmy? The guts? The determination? The five bucks? Join today!

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Thu Feb 07, 2008 10:29

Hell, I was so close :D

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Sun Aug 03, 2008 16:17

Time to revive this thread... What's the pb with following:

Code: Select all


void special_formatted_Err_print(const char* format,...)
{
	int err=errno;
	va_list args;
	int len=0;

        void *buff;
        buff=malloc(MAX_PRINT_LEN);
        if(buff==NULL)
        {
           //errorhandling, out of mem?
        }
	va_start(args,format);
        len=vsnprintf(buff,MAX_PRINT_LEN,format,args);
	va_end(args);

        len+=snprintf
        (
            buff+len,
            MAX_PRINT_LEN-len,
            " %s:%d errno=0x%x",
            __FILE__,
            __LINE__,
            errno 
        );
	
        some_special_print_to_device(buff,len);
     
}
And problem is not in any syntax bug which there may be, since I just invented this example. (Idea is to create a print function for error prints, and which appends file name and line number at the end of the print, and prints the message in some device. (socket, file, pipe, stdout, whatever).

There's now 2 intentional bugs for you to spot. The other is just quite a silly lil thing, which would be corrected if this function was a macro (Why?). The other is related to snprintf and vsnprintf, and is likely to cause a crash at certain point...

User avatar
Maz
Admin emeritus
Posts: 1938
Joined: Thu Mar 16, 2006 21:11
Location: In the deepest ShadowS
Contact:

Post by Maz » Tue Aug 05, 2008 20:55

Pager? Zyx? Anyooone? :rolleyes:

Post Reply