Am I deciphering this right? TIC++ Chap3

So Im reading through thinking in C++ and I got to the reinterpret_cast part in chapter three and have spent a long time staring at this.. I find it odd they used such an example considering structs and arrays with and without pointers arent even discussed at this point in the chapter but anyway, heres the code and my attempt at deciphering, this may be long so please bear with me.. only been at this a week or so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
const int sz = 100;

struct X { int a[sz]; };

void print(X* x) {
  for(int i = 0; i < sz; i++)
    cout << x->a[i] << ' ';
  cout << endl << "--------------------" << endl;
}
int main() {
  X x;
  print(&x);
  int* xp = reinterpret_cast<int*>(&x);
  for(int* i = xp; i < xp + sz; i++)
    *i = 0;
  // Can't use xp as an X* at this point
  // unless you cast it back:
  print(reinterpret_cast<X*>(xp));
  // In this example, you can also just use
  // the original identifier:
  print(&x);
}


Okay so we create a struct of type X containing an array a of size sz(100). When we run int main and create the object x of X type the arrays aren't initialized and produce complete garbage when using the print command. I noticed if I create the object when I create the struct ie: struct X { .. }x; then the arrays are initialized.

Now I understand the reinterpret_cast here is needed to give an int pointer the address of the X type object, its not an implicit conversion so the cast is needed, cool.

Now the loop through me for, well, a loop for a while. I was looking at it thinking, how does the i get anywhere if we're always setting it to zero? also how does the xp+sz work, shouldnt it just be sz?
Lots of testing and outputting of the vars and their addresses I came to the conclusion: the loop sets an int pointer i to the address of the xp which is just the starting address of the x object and the first array index a[0]. i < xp+sz is a weird one cause it adds a value of 10 to a memory location, but I realized it does some conversion and basically sets it so that the loop runs until i < xp + 10*4bits or 0x28. When it sets *i=0 its dereferecening and setting the current value held in those memory locations to zero.

So now our array is initialized and we can use it in the print function. As the program says you must cast it back to use xp or you can use the original identifier for the object &x.

--

Now I also did some playing around and I noticed that I dont need any of this fancy pointer and reinterpret_cast stuff to initialize the object within the array, nor do I have to have the print function take a pointer of an object for it to work.. so what is the purpose of all this other than to highlight some overly complex use of the reinterpret cast function? none of this is needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
void print(X x) {
  for(int i = 0; i < sz; i++)
    cout << x.a[i] << ' ';
  cout << endl << "--------------------" << endl;
}
int main() {
  X x;
  print(x); //garbage
  for(int i = 0; i < sz ; i++) {
    x.a[i] = 0;
  }
  print(x); //initialized and producing zeros
...


this has been a big stumbling block for me, ive handled a lot of this pretty easily and I seem to get the pointers with objects and arrays stuff to some degree, but I dont see the purpose in making something like initializing an array within an object so overly complex that we have to use what is coined as a "very dangerous" cast type? what are the advantages of using the pointers in this case?


Also I have a question about question 18 in this chapter
Create a program that defines two int arrays, one right after the other. Index off the end of the first array into the second, and make an assignment. Print out the second array to see the changes cause by this. Now try defining a char variable between the first array definition and the second, and repeat the experiment. You may want to create an array printing function to simplify your coding.


What exactly does it mean index off the end of the first array into the second? is it saying like if we have two arrays a[10] and b[10] set b[] = a[9] ?? It mentions nothing about memory locations, but if im right once the array is created its memory positions are mapped and cannot be changed, and if the arrays are created one after another b[0] should follow right after a[9] anyway.. which is where I think they are going with adding the char var inbetween the two arrays.. but I just dont know what they mean by index the second off the end of the first :/

Thanks guys, and thanks to anyone who reads my novel :o
Your understanding is correct, but
i < xp + 10*4bits or 0x28
sz is 100, so it will run until i points to a location 400 bytes beyond where xp does (assuming an int is 4 bytes). Numerically, it will only be 100 greater than the value of xp, but the compiler knows the size of an int and will do the rest. I explained this awfully, let me know if it doesn't make sense.

so what is the purpose

It is probably just showing how reinterpret_cast works.

what are the advantages

It's showing a way that you CAN do something. It doesn't mean that it's telling you that you should.

What exactly does it mean

It seems to want you to go out of bounds of the first array, and see what happens to the data in the second. So make two arrays a[x] and b[x], initialize everything to 0, then change the value of a[x+y] and print out the contents of b.
Last edited on
Ok, for the first part. Obviously it's just a weird example of using reinterpret_cast. No one ever would do it like this. So just bear with it. reinterpret_cast is indeed dangerous and often is a sign of poor design. Nevertheless, sometimes it is useful - e.g. to pass some data from one subsystem to another through a generic intermediate layer (imagine something like passing data through TCP/IP - the protocol knows nothing about the data, but server and client do, so client might receive a void* and reinterpret_cast it to something useful).

The loop in the first part is using some pointer arithmetic. i is of type int*, so every time you do i++, the pointer moves to the memory location i + sizeof(int). So it starts at the address of xp, then initializes the value and moves the pointer to the next int. When should this loop end? When we reach the end address of the array. It's exactly at xp + sz. As an example: assume that xp points to the address 10 in memory and sz == 3. During the loop, i will have values 10, 14, 18, 22 (assuming sizeof(int) == 4). The end address 22 can be computed in bytes as the starting address 10 plus sz * sizeof(int) -> 3 * 4 = 12. But again as we use pointer arithmetic the sizeof(int) is automatically accounted for by the compiler based on the type of xp, which is int*. Hope this clears up the loop stuff :)

You are correct about the initialization of the array. However, passing the parameter by value induces additional memory copies. Passing a parameter through pointer or a reference doesn't. Explanation of this should be somewhere in the book so I wont go deeper on this topic :)

Finally, the "index off" thingie. Took me a bit of time to figure this out - wording is a bit weird :) What they want you to do is:

1
2
3
4
int a[10];
int b[10];

a[10] = 24; // Most likely will set b[0] to 24 

Most likely the compiler will put the array b right after the end of a in memory. So writing past the end of array a will cause b to change. However, this depends on many things. It is the decision of the compiler - where in memory to put your arrays. It may depend on the alignment requirements, optimization strategies and many other thing. If you build a debug build (at least in MSVS) you will not see the change in b, but you'll get a runtime check failure - that's because the compiler will put a special data block after the array which, when written over, will signify exactly this problem - writing out of bounds. Anyway, yes, they want you to see how potentially writing out of bounds corrupts other data. That's pretty much it. Another thing is: never ever rely on where you think the compiler will put your variables in the stack (of course you can rely on the layout of structures, single arrays, etc. - but these behaviors are specified in the standard and all compilers follow it - but again it's a topic in it's own).

Enjoy :)
You are mostly right. This example shows how you should not initialize X::a, but it is an example to demonstrate reinterpret_cast. reinterpret_cast allows you to convert freely between pointer types (for more information on type casting, see http://www.cplusplus.com/doc/tutorial/typecasting/), and this is used to convert from X* to int*, exploiting that X::a is the first member in memory. If X::a was declared private, this would still be a way to get access.
The loop that follows basically loops through all elements and assigns them the value 0: As xp is a pointer to the first element of a, xp + sz is the address of the memory just past the last element.
So in this case, there seems to be absolutely no advantage of using dynamic_cast. You have already posted a clean alternative. However, passing constant references/pointers to objects when calling a function is something you may want to do in order to avoid copying much data. Overall I would say that this is an example which demonstrates what you can do with reinterpret_cast, but it doesn't show you a meaningful use case.

As to question 18 I think the author wants you to write to a[size] instead of b[0], if b is directly behind a in memory (or a[size+1] instead of b[1] etc.).

I hope this answer helps you; feel free to ask further questions.
@KRAkatau the appropriate cast from void* to something useful is static_cast.
Yep, bad example indeed :) A better example is here: http://msdn.microsoft.com/en-us/library/e0w9f63b(v=vs.80).aspx
I appreciate the replies guys and the patience with me lol. I had half expected a flurry of noob comments and 'do a search' etc..

@BranFlakes:
Youre right I meant bytes. I was thinking an increment of 1 in the memory location meant one bit but clearly that cant be right because if an int were 4 bits the most it could hold would be 0-16.. and thats certainly not true lol.
I had set sz to 10 for my debugging, so thats why I had that in mind; I just copied the fresh example code for this thread and forgot about sz being 100 in the original.

I guess Ill skip over 18 and work on the last few questions then, aside from the makefile ones.. I dont think with a modern compiler (or non commandline that is) that Ill need to deal with those kind of things.. at least for any of my purposes for a long time.


I do have another question actually, perhaps it should be in another thread but Ill ask it here anyway. the Cin function. I wrote a program which takes numbers from 1 to 1000 and a user input of the number of factors they wish to find. eg user puts in 7, the program lists every number from 1-1000 with a total of 7 factors, and outputs the numers and their factors. Then at the end I have a user option via a cin "y or n" to output the results to a text file.

I am using cin with the overload operator << (not that I really truly understand the whole overload concept yet), and I noticed if I input a character instead of a integer at first the whole program went haywire. So I had to add in some clauses, a cin.clear() and another cin argument which I dont entirely understand.

In anycase if I type 1y2y3y4y5y6y for example, it runs through and finds all the numbers with 1 2 3 4 5 6 factors, and outputs them all to the text file. I guess its kind of handy if this is the type of action you want to happen but its NOT what I want to happen. It seems cin keeps the other inputs in some sort of a buffer, and then automatically retreves them when its called to find such a character, so the first int cin input takes the 1, and the next being a char for the y or n, takes the y, the program loops and it automatically takes the 2 and so on.. is there a reason for this or a way to stop this? I tried adding a cin.clear() after each cin<<int/char but it does nothing, so Im guessing this function doesnt really 'clear' the input as I suspected it would.. my code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

//Finds numbers between 1 and 1000 with a given number of factors
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

inline string toStr(int a){
  return static_cast<ostringstream*>(&(ostringstream()<<a))->str();
}

int main() {
  while(true){
    string outStr;
    int factors;
    int totalNums = 0;
    cout<<"Find numbers between 1 and 1000 with how many factors?"<<endl;
    cin>>factors;
    cout<<endl;    
    //check for invalid entry
    if(!cin){
      cin.clear();
      cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
      cout<<"That's not a number! :(\n\n";
      continue;
    }
    outStr = "Numbers with a total of " + toStr(factors) + " factors:\n\n";
    //begin iterating through numbers
    for(int i = 1; i < 1000; i++){
      int numEvenDivs = 0;
      //iterate through possible factors
      for(int j = 1; j <= i; j++){
        if(i%j == 0){
          //if there are more factors than we're looking for, break out of loop
          if(++numEvenDivs > factors)
            break;
        }
      }
      //display number and its factors
      if(numEvenDivs == factors){
        ++totalNums;
        outStr += "> " + toStr(i) + ": ";
        for(int k = 1; k <= i; k++){
          if(i%k == 0){
            outStr += toStr(k)+ " ";
          }
        }
        outStr += "\n";          
      }
    }
    //if there arent any numbers at all
    if(totalNums == 0){
      cout<<"No such numbers exist!\n\n";
      continue;
    }
    //final output to console
    cout<<outStr<<endl;
    cout<<"A total of "<<totalNums<<" numbers exist with "<<factors<<" factors\n\n";
    //check to see if user wants to output to a text file
    cout<<"Would you like to output the results to a text file, type Y or N"<<endl;
    char getResults;
    cin>>getResults;
    if(getResults == 'Y' || getResults == 'y'){
      ofstream out(string(toStr(factors) + "-factors.txt").c_str());
      out<<outStr; 
      cout<<"Results output!\n\n";
    } else {
      cout<<"\n";
    }
  }
}


cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'):: this is the second command after cin.clear I was referring to. It refers to a standard object numeric_limits with an implicit cast to standard type streamsize.. right? anything in a <> is a cast correct? and then the ::max() I am totally lost, is that part of numeric limits? making it a function within a class within a class? Either way, without this code, upon character entry it still went psycho..
Also static_cast<ostringstream*>(&(ostringstream()<<a))->str() turns an integer into a string using the stringstream, namely the ostringsteam function.. So, what I get here is that, the integer a is overloaded into the ostringstream function, and taking the address of that conversion the str() function within ostringstream object is called, and because we're dealing with addresses at this point its cast to a pointer? I dont think I have this right. The multi line code was so easy and I do understand that, create a stringstream variable, take that variable and overload with your number, then take the ss variable, and call the .str() function and voila you have your string. I guess where I get lost is the whole ostringstream() and the address and pointer bits..

Anyway I guess Im going to finish up questions 25-28 which I should handedly do.. and then move onto chapter four. I don't really like moving past things until I truly understand them, and my above code even kind of bothers me for some of the things I used.. I guess, well, hope, most of my questions might be answered as I delve further into the book.

Thanks again :)
I tried adding a cin.clear() after each cin<<int/char but it does nothing, so Im guessing this function doesnt really 'clear' the input as I suspected it would.. my code is as follows:

Programming by experiment isn't very productive. If you want to know what something does... look it up.

http://www.cplusplus.com/reference/ios/ios/clear/

cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'):: this is the second command after cin.clear I was referring to. It refers to a standard object numeric_limits with an implicit cast to standard type streamsize.. right?

http://www.cplusplus.com/reference/limits/numeric_limits/

anything in a <> is a cast correct?

No. If it doesn't say static_cast, dynamic_cast or reinterpret_cast it isn't a cast. In most other cases you're specifying a type for a template.

static_cast<ostringstream*>(&(ostringstream()<<a))->str()

This is demonstrating the use of an unnamed temporary. The cast is needed because the insertion operator returns a reference to std::ostream and an ostringstream type is needed to access the str() method. Taking the address and using a cast to a pointer seems a little odd. I would've written it:

static_cast<ostringstream&>(ostringstream()<<a).str() ;

Don't be afraid to look stuff up. =P
Last edited on
I think I found another place to use the reinterpret_cast, if anyone else can show me a way to do this problem without it let me know please:


Define a float variable. Take its address, cast that address to an unsigned char, and assign it to an unsigned char pointer. Using this pointer and [ ], index into the float variable and use the printBinary( ) function defined in this chapter to print out a map of the float (go from 0 to sizeof(float)). Change the value of the float and see if you can figure out what’s going on (the float contains encoded data).


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;

void printBinary(const unsigned char val) {
  for(int i = 7; i >= 0; i--) {
    if(val & (1 << i))
      std::cout << "1";
    else
      std::cout << "0";
    }
    std::cout<<endl;
}
int main(){
  double f;
  while(true){
    cout<<"input a float number"<<endl;
    cin>>f;
    unsigned char* fa = reinterpret_cast<unsigned char*>(&f);  
    for(int i = 0; i < sizeof(double); i++) {
      cout<<i<<": ";
      printBinary(fa[i]);
    }
  }
  system("pause");
}


output example:

1
2
3
4
5
3.141
0: 00100101
1: 00000110
2: 01001001
3: 01000000


Obviously.. I cant figure out the encoding lol.


Whoa.. if I print out &fa[i] without a cast to long or int and i type in the float 2.123 my speakers beep three times..

*mindblown*
thanks cire

I do try to look things up, but a lot of the reference pages are pretty hard to follow for someone like me.. not to mention a lot of the coding style on those pages doesnt match the way my book is teaching me to.

for instance the fstream stuff to open a file my book says

ifstream in(filename.txt);

whereas in the reference its something totally different, they make the fstream variable and then use variable.open(), I assume they do the same things, but its stuff like that that really throws me off.

Even in the program I created above that outputs a floats binary encoding I kind of dont get it because I make a pointer to fa, but then when I use the print binary function it takes fa, which should hold memory addresses, but somehow it gets the content of those addresses. Not to mention I never define it as an array but I guess implicitly any char is an array.. little things like this that arent really covered in the book yet they want you to do these things.. it becomes more trial and error than actually knowing what I am doing.

Especially when I get to the cin pages, I looked over those references, but I still dont understand whats going on really, and as far as the int to string conversion goes, thats the code that was in an article on this very website. WHy they wrote it that way I dont know.

Sorry for all the questions, I just dont like using stuff i feel uncomfortable about understanding how it works is all :/ and i dont really have anywhere else to ask :o
Topic archived. No new replies allowed.