vector.data() should return a pointer to the first element, but when I use it on a vector<uint8_t>, it somhow returns somthing else:
int main() {
std::string myString = {"a b c all the way long"};
std::vector<uint8_t> myVec(myString.begin(), myString.end());
std::cout << myVec.data() << std::endl;
std::vector<int> anotherVec = {4,5,2,3};
std::cout<< anotherVec.data() << std::endl;
return 0;
}
program prints:
a b c all the way long
0x124bf00
Why does the first print show all of the vector, and the second print shows the pointer? I was expecting both to print a pointer.
The real issue is that on another big program, when I print vector<uint8_t>.data() with cout, it prints garbage after it (when I look at it in the debugger, I don't see the garbage).
The data() function returns a pointer to the first element.
myString is a vector of uint8_t values, so data() will return a value of type uint8_t*. uint8_t is a type based on char, so the << stream output operator will treat it as a null-terminated string. The problem here is that myVec doesn't contain a null-terminated string, so this is technically undefined behavior.
For anotherVec, that's a vector of int values, which means that data() returns a value of type int*, which has no specific overload for the << stream output operator. Instead, it uses the closest possible overload, which is the one to print generic pointers of type void*.
If you want the first to print the pointer itself, then you need to explicitly cast the pointer to void*:
std::cout << static_cast<void*>(myVec.data()) << '\n';
Related
I'm using C++ to understand how exactly pointers work. I have this piece of code using arrays, which I'm using just to understand how the equivalent works with pointers.
int main() {
int arr[10] = {1,2,3};
char arr2[10] = {'c','i','a','o','\0'};
cout << arr << endl;
cout << arr2 << endl;
}
However when I run this, arr outputs the address of the first element of the array of ints (as expected) but arr2 doesn't output the address of the first element of the array of chars; it actually prints "ciao".
What is it that I'm missing or that I haven't learned yet about this?
It's the operator<< that is overloaded for const void* and for const char*. Your char array is converted to const char* and passed to that overload, because it fits better than to const void*. The int array, however, is converted to const void* and passed to that version. The version of operator<< taking const void* just outputs the address. The version taking the const char* actually treats it like a C-string and outputs every character until the terminating null character. If you don't want that, convert your char array to const void* explicitly when passing it to operator<<:
cout << static_cast<const void*>(arr2) << endl;
Because cout's operator << is overloaded for char* to output strings, and arr2 matches that.
If you want the address, try casting the character array as a void pointer.
There is a standard overload for char* that outputs a NUL terminated string.
While casting is probably a more meaningful approach, you could also use the addressof operator:
cout << &arr2 << endl;
I'm using C++ to understand how exactly pointers work. I have this piece of code using arrays, which I'm using just to understand how the equivalent works with pointers.
int main() {
int arr[10] = {1,2,3};
char arr2[10] = {'c','i','a','o','\0'};
cout << arr << endl;
cout << arr2 << endl;
}
However when I run this, arr outputs the address of the first element of the array of ints (as expected) but arr2 doesn't output the address of the first element of the array of chars; it actually prints "ciao".
What is it that I'm missing or that I haven't learned yet about this?
It's the operator<< that is overloaded for const void* and for const char*. Your char array is converted to const char* and passed to that overload, because it fits better than to const void*. The int array, however, is converted to const void* and passed to that version. The version of operator<< taking const void* just outputs the address. The version taking the const char* actually treats it like a C-string and outputs every character until the terminating null character. If you don't want that, convert your char array to const void* explicitly when passing it to operator<<:
cout << static_cast<const void*>(arr2) << endl;
Because cout's operator << is overloaded for char* to output strings, and arr2 matches that.
If you want the address, try casting the character array as a void pointer.
There is a standard overload for char* that outputs a NUL terminated string.
While casting is probably a more meaningful approach, you could also use the addressof operator:
cout << &arr2 << endl;
If cstring is a pointer, then why can it get a value directly? Secondly, Why wasn't the *cstring's result equal to whole of string? Third, cstring is a non-constant pointer to a constant character, so why change its value and not change its address?
#include <cstdio>
#include <conio.h>
#include <iostream>
using namespace std;
int main()
{
const char* cstring = "string";
cout << cstring << endl << *cstring << endl << &cstring << endl;
cstring = "foo";
cout << cstring << endl << *cstring << endl << &cstring << endl;
_getch();
return 0;
}
If cstring is a pointer, then why can it get a value directly?
The operator << of cout for const char* is specialized to behave that way. It will treat the pointer as a NULL terminated string and will print it instead of the pointer value. For different types you get different behaviour. For char* you have the whole string printed.
Why wasn't the *cstring's result equal to whole of string?
That is because the type of *cstring is char and again, operator << behaves correctly by just printing a single char. a const char* is essentially an array of char.An array is essentially a pointer to the first element of the array. If you use the * operator on a pointer you are accessing whatever the pointer points to. If it points to the first element, well, you get the first element.
Third, cstring is a non-constant pointer to a constant character, so why change its value and not change its address?
As you said, cstring is a non-constant pointer to constant data. You cannot change the place it points to (it is a constant pointer), but you can substitute the content of the pointed data with other stuff. You point to the same location but the content of that cell changes.
If cstring is a pointer, then why can it get a value directly?
Anyone can get the value pointed at by a pointer by dereferencing the pointer. That's what happens when you do std::cout << cstring. The proper overload gets chosen that prints the string represented by cstring assuming that is correctly formed, null-terminated C-style string.
Secondly, Why wasn't the *cstring's result equal to whole of
string?
cstring is a const char*, so *cstring is a const char. Pass that to std::cout and it will call an overload that prints one char. The function that is called internally doesn't even know that this is just one char in a string.
Third, cstring is a non-constant pointer to a constant character, so
why change its value and not change its address?
You can't change the address of a variable. cstring is in a fixed place on the stack. You change the value of cstring, which is the address of the string that it's pointing to (it is now pointing to a different string, which has a different address, "string" of course stil has the same address).
What you probably wanted to try is this:
const char* cstring = "string";
std::cout << (void*)cstring << std::endl;
cstring = "foo";
std::cout << (void*)cstring << std::endl;
Now you can see the different addresses. One is the address of "string" and one is the address of "foo".
char buffer[4];
std::cout << &buffer << std::endl;
std::cout << &buffer[0] << std::endl;
When I run this code the first line is the hex address of first element in the buffer. The second line is four question marks (unless I cast as a null-pointer).
How is the second statement different from the first (semantically, they are the same?)?
Why does the second line appear as question marks and not random garbage characters?
&buffer gives you the address of the buffer, in an appropriate pointer type. That type is char (*)[4].
&buffer[0] gives you the address of the first buffer element (a char), so the address is of type char*.
The standard stream classes have an overload that handles a char const*, but no overload that handles a char (*)[4]. There is however a general overload for pointers, that accepts a void*. So the pointer to array is converted implicitly to a void*, and passed to that overload. You therefore see the address of the buffer.
In the second case, if buffer was initialized properly, you'd see its contents printed (what the "c-string" overload does). However, since you did not initialize it, your code has undefined behavior. The mere attempt to print the buffer has no well defined consequence.
&buffer is the address of the buffer. &buffer[0] is the address of the first character in the buffer. here in your case a garbage value that is because you didn't initialize it. Try to initialize it:
char buffer[] = "Hello there!";
std::cout << &buffer << std::endl;
std::cout << &buffer[0] << std::endl; // print from first element to the end(until the first null-character)
std::cout << &buffer[4] << std::endl; // print from fifth element to the end
The output:
0018FF38
Hello there!
o there!
I think it is a problem of osstream insertion operator << which assumes you to pass a char* and you pass to it the address of a character so as I guess it's a UB.
To get the address of the character you have to cast it to void*:
std::cout << static_cast < void* >(&buffer[0]) << std::endl;
std::cout << static_cast < void* >(&buffer[1]) << std::endl;
The output:
0018FF38
0018FF39
To confirm that it's an ostream << issue try to use printf:
printf("&buffer[0]: %p \n", &buffer[0]);
The output:
&buffer[0]: 0018FF38
I understand from here that the name of an array is the address of the first element in the array, so this makes sense to me:
int nbrs[] = {1,2};
cout << nbrs << endl; // Outputs: 0x28ac60
However, why is the entire C-string returned here and not the address of ltrs?
char ltrs[] = "foo";
cout << ltrs << endl; // Outputs: foo
Because iostreams have an overload for char * that prints out what the pointer refers to, up to the first byte that contains a \0.
If you want to print out the address, cast to void * first.
cout has operator<<() overloaded for char* arrays so that it outputs every element of the array until it reaches a null character rather than outputting the address of the pointer
cout, and generally, C++ streams, can handle C strings in a special way. cout operators <<, >> are overloaded to handle a number of different things, and this is one of them.