I have a method in C++ that receives a char * data as a parameter, like this:
bool Whatever::method(char * data) { ... }
Now, I want to print the contents of that array. If I try:
for (int i = 0...) {
cout << *(data+i) << endl;
}
it will only print blank spaces. No garbage, just blanks. But if I cast to int * and then dereference, it kind of works (but of course it prints the values as integers):
for (int i = 0...) {
cout << *(int*)(data+i) << endl;
}
What am I doing wrong here? Thanks!
Edit:
The contents of the array are the following:
An enum
A char[6]
A long
What I get is a blank space per char. Even if I remove the for loop and try something like cout << *data << endl; (which should print the first character) it will still print a blank.
I understand that the long won't be correctly printed if I interpret it as a char, and the enum is just a number after all, but anyway I should be able to interpret them as characters... Please correct me if I'm wrong.
The expression
*(int*)(data+i)
casts the char* pointer formed by data+i to int*, and dereferences. This would access sizeof(int) char-values as an int, except that it's Undefined Behavior so it might really do anything. In particular at the end of the array.
If you're interested in outputting the numerical values, instead do
+data[i]
which promotes the char value to int.
Related
I'm rather new to C++ and while working with a pointer to a char array (C style string) I was confused by its behavior with the ostream object.
const char* items {"sox"};
cout << items << endl;
cout << items[0] << endl;
cout << *items << endl;
cout << &items << endl;
cout << &items[1] << endl;
Running this leads to:
sox
s
s
0x7fff2e832870
ox
In contrary to pointer of other data types, printing the variable doesn't output the address, but the string as a whole. By what I understand, this is due to the << operator being overloaded for char arrays to treat them as strings.
What I don't understand is, that cout << &items[1] prints the string from index 1 onward (ox), instead of the address of the char at index 1. Is this also due to << operator being overloaded or what is the reason for this behavior?
The type of &items[1] is const char *. Therefore the const char * overload of operator << is used, which prints the string from index 1 onwards.
OTOH, the type of &items is const char **, for which no specific overload exists, so the address of items is printed (via the const void * overload).
Back in the olden days, when C ran the world, there was no std::string, and programmers had to make do with arrays of char to manage text. When C++ brought enlightenment (and std::string), old habits persevered, and arrays of char are still used to manage text. Because of this heritage, you'll find many places where arrays of char act differently from arrays of any other type.
So,
const int integers[] = { 1, 2, 3, 4 };
std::cout << integers << '\n';
prints the address of the first element in the array.
But,
const char text[] = { 'a', 'b', 'c', '\0' };
std::cout << text << '\n';
prints the text in the array text, up to the final 0: abc
Similarly, if you try to print addresses inside the array, you get different behavior:
std::cout << &integers[1] << '\n';
prints the address of the second element in th array, but
std::cout << &text[1] << '\n';
prints the text starting at the second character of the array: bc
And, as you suspected, that's because operator<< has an overload that takes const char* and copies text beginning at the location pointed to by the pointer, and continuing up to the first 0 that it sees. That's how C strings work, and that behavior carries over into C++.
items[1] is the second character of the array and its address, i.e. &items[1], is a pointer to the second character (with index 1) as well. So, with the same rule that you have mentioned for operator <<, the second character of the string till the end is printed.
I have this program:
#include <iostream>
#include <conio.h>
#include <string.h>
using namespace std;
int main()
{
char char1[30] = "ExtraCharacter", char2[30] = "Character", *p;
p = strstr(char1, char2);
cout << "p: " << p << endl;
cout << "char1: " << char1 << endl;
cout << "(p-char1): " << (p-char1) << endl;
return 0;
}
When I run it, I get:
p: Character
char1: ExtraCharacter
(p-char1): 5
as expected.
But this is not the problem, I'm not sure why "Character" - "ExtraCharacter" is an integer (5)? Perhaps not an integer, but a number/digit anyways.
Actually I don't understand why is "Character" stored in p, and not the memory address.
If I understood well from a book, strstr() returns a memory address, shouldn't it be more like a strange value, like a hex (0x0045fe00) or something like that? I mean, it's cout << p not cout << *p to display the actual value of that memory address.
Can someone explain me how it works?
P.S.: I apologize if the title is not that coherent.
But this is not the problem, I'm not sure why "Character" - "ExtraCharacter" is an integer (5)?
You subtract one pointer from another and result - number, distance from char char1 points to to char p points to. This is how pointer arithmetic works.
Note: this subtraction is only valid when both pointers point to the same array (or behind the last element), which is the case in your code, but you need to be careful. For example if strstr() does not find susbtring then it would return nullptr and your subtraction will have UB. So at least check p before subtracting (and passing nullptr to std::cout would have UB as well)
If I understood well from a book, strstr() returns a memory address, shouldn't it be more like a strange value, like a hex (0x0045fe00) or something like that? I mean, it's cout << p not cout << *p to display the actual value of that memory address.
Yes p is a pointer aka memory adress. std::ostream has special rule how to print pointers to char - as strings, because strings in C stored that way. If you want to see it as a pointer just cast it:
std::cout << static_cast<void *>( p );
then you will see it as an address.
To display address, you have to cast char* to void*:
std::cout << "p: " << static_cast<const void*>(p) << std::endl;
Demo
For std::basic_ostream (type of cout), character and character string arguments (e.g., of type char or const char*) are handled by the non-member overloads of operator<< which are being treated as strings. char[30] will be decayed to const char* argument and basic_ostream will output the null terminated string at the address of the pointer.
As for (p-char1), the result of subtracting two pointers is a std::ptrdiff_t. It is an implementation-defined signed integer. That's why the output is 5
I have a function called SearchArray() which calls another function called SearchRecords(char StudentNo[]) to check the database array of gRecs for a match in student numbers.
When i run the debugger the value of StudentNo is being shown as StudentNo = 0x22fde0 "12345678" if StudentNum = "12345678".
What are these additional characters?
SearchArray() function
void SearchArray(){
char studentNum[8];
cout << "Enter student number: ";
cin >> studentNum;
char i = SearchRecords(studentNum);
if (gRecs[i].studentNumber != studentNum){
cout << "Record not found" << endl;
}
else {
PrintRecord(i);
}
}
SearchRecords() function
int SearchRecords(char StudentNo[])
{
for (int i = 0; i < gNumRecs; i++){
if(gRecs[i].studentNumber == StudentNo)
{
return i;
}
}
return -1; //not found
}
Do you mean the "0x22fde0"? Those aren't in your character array, your character array only contains the part in quotes ("12345678"). The hexadecimal number 0x22fde0 is the address of the first character. In C/C++, any array is really just a pointer to the first element: the value of the variable is the address of the first element. So the debugger is showing you that address value. But it also knows that character arrays usually store strings, so it is also helpfully showing you the contents of that array as a string.
As this comment notes, you're comparing pointers not strings. You'll save yourself many headaches by changing your studentNumber type to std::string. This will allow you to use comparison operators(==,!=,<,<=,>,>=) with either a std::string or a raw string(char*) on the right side. I highly recommend reading up on strings at tutorialspoint.com and cplusplus.com.
When posting in the future, please post any relevant custom data structures(such as the layout of your gRecs element type), it helps us solve the problem faster.
I understand that an array of chars is different to a cstring, due to the inclusion of a suffixing \0 sentinel value in a cstring.
However, I also understand that, in the case of a cstring, an array of chars, or any other type of array, the array identifier in the program is a pointer to the array.
So, below is perfectly valid.
char some_c_string[] = "stringy";
char *stringptr;
stringptr = some_c_string; // assign pointer val to other pointer
What I don't understand is why std::cout automatically assumes I want to output the value of each element in either a cstring, or an array of chars, rather than the hex address. For example:
char some_c_string[] = "stringy"; // got a sentinel val
char charArray[5] = {'H','e','l','l','o'}; // no space for sentinel val \0
char *stringptr;
stringptr = some_c_string;
int intArray[3] = {1, 2, 4};
cout << some_c_string << endl << charArray << endl
<< stringptr << endl << intArray << endl;
Will result in the output:
stringy
Hello
stringy
0xsomehexadd
So for the cstring and the char array, std::cout has given me the value of each element, rather than the hex address like with the int array.
I guess this became a standard in C++ for convenience. But can someone please expand on 1) When this became standard. 2) How std::cout differentiates between char/cstrings and other arrays. I guess it uses sizeof() to see it's is an array of single bytes, and that value of each array element is an ASCII int value to identify an array of chars/cstring.
Thanks! :D
There is nothing fancy going on. The operator<< has a special overload for char*, so that you can do std::cout << "Hello World";. It's been like that since day 1 of c++.
For anything besides char*, the pointer address is displayed as hex.
If you want to display the address of a char*, simply cast it to void*, ie
std::cout << (void*)"Hello World";
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
char array[10];
for(int i = 0; i<10;i++)
{
array[i] = 'a' + i;
}
char* test = array;
printf("%x\n", test);
cout << hex << test << endl;
}
The output for this is:
bffff94e
abcdefghijN???
Why is it not printing the same thing?
cout << hex << test << endl;
It prints the string, not the address. It is because there is an overload of operator<< which takes char const* as argument and this overload treats the argument as string.
If you want to print the address, cast the argument to void* so that other overload of operator<< will be invoked which will print the address.
cout << hex << static_cast<void*>(test) << endl;
will print the address, in hexadecimal format.
Note that hex stream-manipulator is not needed here, as the address will be printed in hexadecimal format anway. So
cout << static_cast<void*>(test) << endl;
is enough.
Because your program has undefined behavior. And because you ask it to
print different things.
Your invocation of printf is illegal, and results in undefined
behavior (and is a good example of why you should never use printf).
Your format specifier says to extract an unsigned int from the
argument list, and output that in hexadecimal. Passing it anything but
an unsigned int is undefined behavior. As it happens, given the way
varargs are generally implemented, if you're on a machine where
unsigneds and pointers have the same size, you'll probably output the
value of the pointer, treating its bits as if it were an unsigned.
Other behaviors are certainly possible, however. (If I'm not mistaken,
g++ will warn about this construct; it's also possible that on some
platforms, it will crash.)
In the case of std::cout, you're passig it a char*. By definition,
the char* is treated as a '\0' string, not as a pointer (and
certainly not as an unsigned int). And again, you have undefined
behavior, since your char* doesn't point to a '\0' terminated string;
you never put a '\0' at the end. (This probably explains the "N???"
you see at the end of your output. But again, undefined behavior is,
well, undefined. The code could just as easily have crashed.)
Finally, you're using both printf and std::cout; the results are not
really specified unless you do a flush of the stream between the two.
(In practice, if you're outputting to an interactive device, the flush
should occur when you output the '\n' character. If you redirect the
output to a file, however, you're likely to get something different.)
It's not clear what you want. If you want to output the address of
array, it would be:
printf( "%p\n", test );
std::cout << static_cast<void*>( test ) << std::endl;
If you want to output the string you've generated, then append a '\0' to
the end of it (without overflowing the buffer), and then:
printf( "%s\n", test );
std::cout << test << std::endl;
I'm not sure what you're trying to make "hex"; there is no such thing as
a hex representation of a string, and the representation of a pointer is
implementation defined, and not required to take into account any
formatting parameters in iostream. (Typically, on most modern machines,
it will be hex. But I've worked on more than a few where it would be
octal, and at least one where it wouldn't be just a number, regardless
of the base.) If you want a hex dump of array, you'll have to loop,
outputting each value as an unsigned in hex:
for ( int i = 0; i < 10; ++ i ) {
printf( "%x", static_cast<unsigned char>( test[i] ) );
}
printf( "\n" );
std::cout.setf( std::ios_base::hex, std::ios::basefield );
for ( int i = 0; i < 10; ++ i ) {
std::cout << static_cast<unsigned>( static_cast<unsigned char>( test[i] ) );
}
std::cout.setf( std::ios_base::dec, std::ios::basefield );
std::cout << std::endl;
Finally: a word about the casts: plain char may be either signed or
unsigned; if it is signed, converting it to an int or an
unsigned, might produce either a negative value (int) or a very
large positive value (unsigned). Thus, the first conversion to
unsigned char, which guarantees a result in the range [0, UINT_MAX].
Second, of course, we have to convert the unsigned char to unsigned:
in the case of printf, because we would otherwise have undefined
behavior, but the conversion is implicit, since passing an unsigned
char as a vararg automatically promotes it to unsigned; and
in the case std::cout, because the rules are that any character
type be output as a character, not as a numerical value (and since the
type is used here in function overload resolution, and is not being
passed to a vararg or an unsigned, there is no implicit conversion).
test itself is a pointer, i.e. it stores an address. Your printf statement prints the hexadecimal value of that address.
The cout << statement then prints the entire string, because the std::hex manipulator does not affect the way strings are printed. It only affects the way integers are printed.
What you can do is
Loop through the characters of the array
Convert each to an integer and print using the std::hex manipulator
That would look like this:
for (int i = 0 ; i < 10 ; ++i)
std::cout << std::hex << static_cast<int>(array[i]) << '\n';
cout << HEX <<
can't be used to a char* to print a hex char string,
but you can use it for int ,double,float,etc.
And, as you second print, why the string has some garbled strings is that you haven't gived
a '\n' to the string which means the end of string