What is the meaning of the struct variable's name?
In other words, when i tried code :
typedef struct enr
{
int a ;
char b ;
}enr ;
int main()
{
enr x ;
printf(" x = %d\n",x) ;
printf(" x.a = %d\n",x.a);
return 0 ;
}
I get : 38 for x and a.x both ! so I get the first field of the structure as a content of x.
Can any one tell me what's happen in the general case (when the first variable was an array, char, or something else)?
enr is never initialized in your code, so the values of a and b are whatever happened to be in the memory before the object was constructed there. To fix this, use
enr x = {1, 'a'};
You get 38 in both case, because your struct is a POD - plain old data. Therefore, there is nothing more to you struct than an int and a char together. Because C++ does not reorder struct elements, the struct x is at the same address in memory as its first element, x.a. So when you printf them, you print the very same piece of memory.
Note that printing the struct type (printf(" x = %d\n",x)) via %d is technically undefined behaviour (by definition of printf). You get the same results here because enr is a POD and the compiler can somehow work around with that.
Another side note: In C++ a struct is a named type. So it is enough to just write struct enr {...}; The typedef you used is an old C-style.
C has no knowledge of structure member types at runtime. But you told it what the type was with the "%d" in your printf. It printed the value of the integer at x.a not because a was declared to be an integer, but because you told it to. Likewise, x without the member refers to the structure as a whole, but since its address is the same as the address of its first member, and you told it to look for an int there, it found one. If your printfs had used "%f", it would have printed a floating point number represented by the bits at that address for both expressions.
Related
I'm trying to debug a small C++ program using gdb, but may be getting hung up on some pointer arithmetic:
A* get(int) returns a pointer to an instance of a class A I've defined. Internally, get(int) references an array of A, returning:
class A_list {
private:
A* A_array;
int count;
public:
A_list(int c): count(c) { A = new A[c]; }
void insertAt(A a, int idx) {
A_array[idx] = a;
}
A* get(int);
};
A* A_list::get(int idx) {
...
A* result = A_array + idx;
return result;
}
presumably, when dealing with an array of A, I can simply add the index (times the size of a single A) to get the address of the idx'th.
This seems to work as expected. However, when calling get(int) from within another member function of A_list, I watch the value assignment in gdb and see two different values:
void A_list::foo() {
A* a = nullptr; // I declare my pointer, and initialize to 0x0
...
a = get(0); // I store the address of `A_array[0]`
The gdb watchpoint outputs:
Old value = (Number *) 0x0
New value = (Number *) 0x55555556b2c0
However, when I print the address stored in a, I get a completely different value, with an unrecognized message attached.
(gdb) p a
(Number *) 0x7ffff7b4e5c0 <_IO_file_overflow+256>
attempting to dereference any of the member values gives unexpected results
I can't find <_IO_file_overflow+256> defined anywhere in the gdb sources. What does it mean?
Why might the value stored in a appear to be different from the value returned when get() is called from inside a member function of A_list? From outside (eg - in main()) I get the expected value.
Edit 9-08:
Changed assignment in get() based on feedback. Still getting the same arbitrary address when I return from the get() function.
When doing pointer arithmetic, it's done in elements and not in units of bytes.
Therefore the multiplication with sizeof(A) is invalid and wrong: The expression A_array + (idx * sizeof(A)) should be plain A_array + idx.
Or you could be explicit and return &A_array[idx].
All this means that for any pointer or array a and (valid) index i, the expression *(a + i) is exactly the same as a[i]. And from that follows that &a[i] will be exactly the same as a + i.
To answer your last question -- <_IO_file_overflow+256> is telling you gdb's best guess as to what that address (0x7ffff7b4e5c0) refers to -- in this case, the address is pointing into some shared libaray, and the symbol _IO_file_overflow is the closest symbol defined in that library (and specifically, this address is 256 bytes past that symbol). This looks to be part of libc.
You can get more detail about what addresses correspond to what in your program by examining the file /proc/<pid>/maps -- you just need to know the pid of the process you are debugging and you can look at that file in another window.
As to why you're getting this odd value when it looks like you've just assigned a different value, it may be that gdb is getting confused and you have another a defined somewhere and gdb is printing that. Or you may have incomplete/incorrect debugging info in your program -- make sure that you compile with -O0 -g if you want accurate debug info.
So to this is part 2 of a question I asked and was answered yesterday. So today I am coming back with a part 2. I am not sure if this should be this somewhere else so if a moderator wants to move it feel free.
So I am not going to reintroduce my problem here, so please go read part 1
Iterating through a vector of stucts's members with pointers and offsets
So I have come up with a solution to the problem so let me post a modified snippet of code that represents the solution I am going for,
#include <iostream>
#include <vector>
// knows nothing about foo
class Readfoo
{
private:
int offSetSize;
char* pchar;
public:
void SetPoint(double* apstartDouble, int aoffSetSize)
{
offSetSize = aoffSetSize;
pchar = static_cast<char*> (static_cast<void*>(apstartDouble));
};
const double& printfoo(int aioffset) const
{
return *(static_cast<double*> (static_cast<void*>(pchar + aioffset*offSetSize)));
};
};
// knows nothing about readFoo
struct foo
{
int a[5];
double b[10];
};
int main()
{
// populate some data (choose b [2] or other random entry.).
std::vector<foo> bar(10);
for(int ii = 0; ii < bar.size(); ii++)
bar[ii].b[2] = ii;
// access b[2] for each foo using an offset.
Readfoo newReadfoo;
newReadfoo.SetPoint(&(bar[0].b[2]), sizeof(foo)/sizeof(char));
for(int ii = 0; ii < bar.size(); ii++)
std::cout<<"\n"<<newReadfoo.printfoo(ii);
return 0;
}
This, in my opinion, is legal, well I suppose that is what I am asking. Since now, in essence, I am converting my 'interpretation' of the struct foo and the vector bar (an array of foos) into a single array of bytes, or chars.
I.e. In this interpretation the data structure is a single array of chars, of foo size times bar size. When I iterate through this with an integral type I am in essence moving to some hypothetical char element (point 4.2 in the answer to part 1). The printfoo function then combines the next 8 bytes to form a double to return.
So is this legal and other than moving out of bounds of the bar vectors is there any reason why this will not work (I have tested it and it has yet to fail.)?
So is this legal ...
No it is not.
In the following expression:
pchar + aioffset*offSetSize
you manipulate pchar as if it were a pointer to a char array, which it is not (it's a pointer to a double array). And this is undefined behavior:
[expr.add]/6
For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar, the behavior is undefined. [ Note: In particular, a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type. — end note ]
In your case P is pchar and has type pointer to char but the array element it points to is a double.
... and other than moving out of bounds of the bar vectors is there any reason why this will not work (I have tested it and it has yet to fail.)?
Yes: Does the C++ standard allow for an uninitialized bool to crash a program?
To go further: pointer manipulation in C++ is a red flag. C++ pointer manipulation is dark magic which will burn your soul and consume your dog. C++ offers a lot of tools to write generic code. My advice: Ask about what you're trying to achieve rather than about your attempted solution. You'll learn a lot.
If you want to declare an int you do for instance
int x;
You could after assign a value to x (or "define" x) for instance as follows :
x = 3;
Of course, you could have done directly
int x = 3;
There are types whose variables should be declared and defined at the same time, for instance
const double y = 2.3;
as well as type whose variables you simply can't declare and define at the same time, for instance a pointer to an array of three char's :
typedef char (*pc3)[3];
char c3[3] = "ok";
pc3 apc3 = &c3;
(Am I wrong on the two previous examples ? Is there a one-liner (only one semi-column allowed) for the last one ?)
Consider now the following function pointer definition :
typedef int (*ipfunci)(int);
ipfunci fptr = &f; // where f is some int -> int function
(no one-liner for this as far as I know). Perfectly legal of course, but what about
typedef int (ifunci)(int);
Perfectly legal as well, but you can't define a variable of "type" 'ifunci' after having declared it, and what's it's use ?
This boils down to my real question : looking at
typedef char (*pc3)[3];
typedef int (*ipfunci)(int);
one sees an analogy between the two definitions, if one decides to see a size 3 array of char's as a function
0 -> char
1 -> char
2 -> char
One could also see
typedef int * pi ;
as the definition of the "type" pi as constant function with value equal to an int.
How far does this synthactic and functional analogy go ? What is behind types whose definitions really require a typedef : are they systematically "functional" types ?
This question already has answers here:
What are the differences between a pointer variable and a reference variable?
(44 answers)
Closed 7 years ago.
I have a few questions. This isn't homework. I just want to understand better.
So if I have
int * b = &k;
Then k must be an integer, and b is a pointer to k's position in memory, correct?
What is the underlying "data type" of b? When I output it, it returns things like 0x22fe4c, which I assume is hexadecimal for memory position 2293324, correct?
Where exactly is memory position '2293324'? The "heap"? How can I output the values at, for example, memory positions 0, 1, 2, etc?
If I output *b, this is the same as outputting k directly, because * somehow means the value pointed to by b. But this seems different than the declaration of b, which was declared int * b = k, so if * means "value of" then doesn't mean this "declare b to the value of k? I know it doesn't but I still want to understand exactly what this means language wise.
If I output &b, this is actually returning the address of the pointer itself, and has nothing to do with k, correct?
I can also do int & a = k; which seems to be the same as doing int a = k;. Is it generally not necessary to use & in this way?
1- Yes.
2- There's no "underlying data type". It's a pointer to int. That's its nature. It's as data type as "int" or "char" for c/c++.
3- You shouldn't even try output values of memory which wasn't allocated by you. That's a segmentation fault. You can try by doing b-- (Which makes "b" point to the "int" before it actual position. At least, to what your program thinks it's an int.)
4- * with pointers is an operator. With any data type, it's another data type. It's like the = symbol. It has one meaning when you put == and another when you put =. The symbol doesn't necesarilly correlates with it meaning.
5- &b is the direction of b. It is related to k while b points to k. For example, if you do (**(&b)) you are making the value pointed by the value pointed by the direction of b. Which is k. If you didn't changed it, of course.
6- int & a = k means set the direction of a to the direction of k. a will be, for all means, k. If you do a=1, k will be 1. They will be both references to the same thing.
Open to corrections, of course. That's how I understand it.
In answer to your questions:
Yes, b is a pointer to k: It contains the address of k in the heap, but not the value of k itself.
The "data type" of b is an int: Essentially, this tells us that the address to which b points is the address of an int, but this has nothing to do with b itself: b is just an address to a variable.
Don't try to manually allocate memory to a specific address: Memory is allocated based of the size of the object once initialized, so memory addresses are spaced to leave room for objects to be allocated next to each other in the memory, thus manually changing this is a bad idea.
* In this case is a de-reference to b. As I've said, b is a memory address, but *b is what's at b's address. In this case, it's k, so manipulating *b is the same as manipulating k.
Correct, &b is the address of the pointer, which is distinct from both k and b itself.
Using int & a = k is creating a reference to k, which may be used as if it were k itself. This case is trivial, however, references are ideal for functions which need to alter the value of a variable which lies outside the scope of the function itself.
For instance:
void addThree(int& a) {
a += 3;
}
int main() {
int a = 3; //'a' has a value of 3
addThree(a); //adds three to 'a'
a += 2; //'a' now has a value of 8
return 0;
}
In the above case, addThree takes a reference to a, meaning that the value of int a in main() is manipulated directly by the function.
This would also work with a pointer:
void addThree(int* a) { //Takes a pointer to an integer
*a += 3; //Adds 3 to the int found at the pointer's address
}
int main() {
int a = 3; //'a' has a value of 3
addThree(&a); //Passes the address of 'a' to the addThree function
a += 2; //'a' now has a value of 8
return 0;
}
But not with a copy-constructed argument:
void addThree(int a) {
a += 3; //A new variable 'a' now a has value of 6.
}
int main() {
int a = 3; //'a' has a value of 3
addThree(a); //'a' still has a value of 3: The function won't change it
a += 2; //a now has a value of 5
return 0;
}
There are compliments of each other. * either declares a pointer or dereferences it. & either declares a (lvalue) reference or takes the address of an object or builtin type. So in many cases they work in tandem. To make a pointer of an object you need its address. To use a pointer as a value you dereference it.
3 - If k is a local variable, it's on the stack. If k is a static variable, it's in the data section of the program. The same applies to any variable, including b. A pointer would point to some location in the heap if new, malloc(), calloc(), ... , is used. A pointer would point to the stack if alloca() (or _alloca()) is used (alloca() is similar to using a local variable length array).
Example involving an array:
int array_of_5_integers[5];
int *ptr_to_int;
int (*ptr_to_array_of_5_integers)[5];
ptr_to_int = array_of_5_integers;
ptr_to_array_of_5_integers = &array_of_5_integers;
Why this program only works when I initialize a and b.
I want to pass it without initializing a and b, for example:
numChange(10,15);
Is this possible ?
#include <iostream>
using namespace std;
void numChange(int *x,int *y)
{
*x = 99;
*y = 77;
}
int main()
{
numChange(10,15);
//int a=10;
//int b=15;
//numChange(&a,&b);
cout<<a<<" , "<<b<<endl;
return 0;
}
Because you have defined your function to receive pointers, but when you call that function you are trying to pass an int.
The compiler is expecting memory addresses and you are trying to pass constants.
It does not make sense, you are trying to do something like 10 = 99; 15 = 77;?
numChange(10,15);
//int a=10;
//int b=15;
It seems that you are hopping that a = 10 = 99 and b = 15 = 77;
If this was possible, it means that I could never (after the call of numChange(10,15);) make a variable to actually have the value 10 because 10 is "pointing" to 99 (is not).
Recall: a pointer is an integer containing a location in memory.
This:
int a, b;
...
a = b;
copies the integer stored at the memory location reserved for 'b' to
the memory location reserved for 'a'.
This:
int *a, b;
...
a = &b;
stores the location of 'b' in 'a'. Following it with this:
*a = 42;
will store 42 in the memory location stored in 'a', which is the
variable 'b'.
Now, let's look at your code. This:
void numChange(int *x,int *y)
tells the compiler that 'numChange' will be called with two
pointers--that is, memory addresses. This part:
*x = 99;
*y = 77;
then stores two integers at the locations given in 'x' and 'y'.
When you call:
numChange(10,15);
the arguments are integers instead of memory location. However under
the hood, memory locations are also integers so the compiler converts
the arguments to pointers. Effectively, it's doing this:
numChange((int *)10, (int*)15);
(It should issue a warning when this happens, since it's almost never
a good idea, but it will do it.)
Basically, your call to 'numChange' tells it that there are integer
variables at memory addresses 10 and 15, and 'numChange' carries on
and stores integers at those memory locations. Since there aren't
variables (that we know of) at those locations, this code actually
overwrites some other data somewhere.
Meanwhile, this code:
int a=10;
int b=15;
numChange(&a,&b);
creates two integer variables and then passes their addresses in
memory to 'numChange'. BTW, you don't actually need to initialize
them. This works too:
int a, b;
numChange(&a,&b);
What's important is that the variables are created (and the compiler
sets aside RAM for them) and that their locations are then passed to
'numChange'.
(One aside: I'm treating variables as always being stored in RAM.
It's safe to think of them this way but modern compilers will try to
store them in CPU registers as much as possible for performance
reasons, copying them back into RAM when needed.)