vector pointer to an element

Pages: 12
It looks like you've got the fundamentals down!

I had some comments on your program:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <iostream>
using namespace std;

int main()
{
	char myCharArray[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0'};

        // ptrArray has the type pointer-to-char, that is char*
        // myCharArray has type array of 12 char, that is char[12]
        // it is implicitly converted to a pointer to char by means of array-to-pointer conversion
	char* ptrArray = myCharArray;
	
        // &myCharArray has type pointer-to-array of 12 char, that is char(*)[12]
        // this is not the same as a pointer to the first element of the array, 
        // since the latter would be a pointer to char, that is char*
	cout << "&myCharArray = " << &myCharArray << endl;
       
        // By operator precedence &myCharArray[n] is treated as &(myCharArray[n]), 
        // By the equivalence given before that's the same as &(*(myCharArray + n))
        // These expressions have type pointer-to-char, char*, and are therefore 
        // treated as zero-terminated strings by cout<<
	cout << "&myCharArray[0] = " << &myCharArray[0] << endl;	//<<<<<<<<<<<<<<<<<<<<<< prints "Hello World"
	cout << "&myCharArray[1] = " << &myCharArray[1] << endl;	//<<<<<<<<<<<<<<<<<<<<<< prints "ello World"
	cout << "&myCharArray[2] = " << &myCharArray[2] << endl;	//<<<<<<<<<<<<<<<<<<<<<< prints "llo World"

        // recall that ptrArray is not a pointer to the array but a pointer to the first element of the array
        // to print an unchanged representation of the pointer's value you should convert to void* and not unsigned int*
        // because of alignment considerations
        // 
	cout << "(unsigned int*)ptrArray = " << (unsigned int*)ptrArray << endl;
	cout << "(unsigned int*)ptrArray = " << (unsigned int*)(ptrArray+ (sizeof(char))) << endl;
	cout << "(unsigned int*)ptrArray = " << (unsigned int*)(ptrArray+1) << endl;
	cout << "(unsigned int*)ptrArray = " << (unsigned int*)(ptrArray+2) << endl;
	cout << "__________________________________________\n";
	
	//Address for every index
        // did you intend not to print the address of the last element in the array (that contains the zero byte)
	for (int i = 0; i < sizeof(myCharArray) - 1; ++i )
		cout << "(unsigned int*)ptrArray" << "[" << i << "] =" << (unsigned int*)(ptrArray+i) << endl;
	
	cout << "ptrArray = " << ptrArray << endl;	//"Hello World"
	
	//sizeof()
	cout << sizeof(char) << endl;			// = 1
	cout << sizeof(myCharArray[0]) << endl;	// = 1
	cout << sizeof(myCharArray[1]) << endl;	// = 1
	cout << sizeof(myCharArray[2]) << endl;	// = 1
	
	cout << sizeof(ptrArray) << endl;		// = 8
	cout << sizeof(unsigned int*) << endl;	// = 8
	cout << sizeof(char*) << endl;			// = 8
	cout << "__________________________________________\n";
	
	//Interesting, can cast into any type
         
        // You can't do anything with the resulting pointers.
        // Attempting to de-reference the resulting pointers would yield undefined behavior.
        // Accessing an object through a pointer of the wrong type is called pointer type punning
        // And it violates a clause sometimes called the strict aliasing rule
        // For the actual rules see [basic.lval] https://timsong-cpp.github.io/cppwp/n4659/basic#lval-8
	cout << (int*)ptrArray << endl;
	cout << (long long*)ptrArray << endl;
	cout << (short int*)ptrArray << endl;
	cout << (double*)ptrArray << endl;
	cout << (long double*)ptrArray << endl;
	cout << (float*)ptrArray << endl;
	cout << (string*)ptrArray << endl;
	
	cout << sizeof((int*)ptrArray) << endl;			//8
	cout << sizeof((long long*)ptrArray) << endl;	//8
	cout << sizeof((short int*)ptrArray) << endl;	//8
	cout << sizeof((double*)ptrArray) << endl;		//8
	cout << sizeof((long double*)ptrArray) << endl;	//8
	cout << sizeof((float*)ptrArray) << endl;		//8
	cout << sizeof((string*)ptrArray) << endl;		//8
	
	cout << "__________________________________________\n";
	
        // Pointers-to-char are treated specially by std::string
        // There is overloading here - the function that is overloaded is std::string::string
	string strHello = ptrArray;
	cout << "strHello = " << strHello << endl;		//"Hello World"
	
	//void* intAddress = ptrArray;		//Still does not give address, even without a cout <<
	//unsigned int* intAddress = (unsigned int*)ptrArray;
	void* intAddress = (unsigned int*)ptrArray;
	cout << intAddress << endl;
	cout << (unsigned int*)ptrArray	<< endl;
	

	char charK = 'k';
	cout << charK << endl << endl;

        // &charK has type pointer-to-char, char*, and is therefore 
        // treated as a zero-terminated string by cout<<
	//cout << &charK << endl << endl;     //does not work

        // I think you wanted something like 
        // cout << (void*)&charK << endl; 
	cout << (unsigned int*)charK << endl; //Gives [Warning] cast to pointer from integer of different size [-Wint-to-pointer-cast]
	
	return 0;
}
Last edited on
char = is a built-in type

Yes. It's a so called fundamental type.
char is technically just an integer type, but it's often used for characters so many library functions will treat it differently.

and char array[] are arrays of built-in types

A char array is a so called compound type because it's defined in terms of another type.

but they are not classes or vectors

Yes.

std::vector is a class template (a template for generating classes) so std::vector<T> (where T is some type) is technically a class.

string = is a class.

std::string is a class.
But when just writing string in a sentence it can often mean any kind of string. C string, std::string, std::string_view, etc.

A pointer to a char array, points to what exactly? Like the other pointers, to the address of the first index?

Assuming you mean a char*, it can point to any element in the array. But the implicit conversion from array to pointer gives you a pointer to the first element in the array. This is the case for all arrays, not just char arrays.

Because it knows the first address, but returns the whole c-style string because of the need to support legacy C and convenience.

There is no difference in how the pointers work. They're just treated differently by various functions.

BUT even outside the cout the way the pointer to the char array behaves holds true and there is NO OVERLOADING here!....so the below line sends the whole string and not the address:

string strHello = ptrArray; // prints out "Hello World" and doesn't give address, because legacy needs this format for whole c-style string...it is just the way it is!

In this case it's the constructor of std::string that treats the char* that is passed to it in this way. It assumes its a C string (null-terminated character array). If it isn't (i.e. the array is not null-terminated) it will lead to undefined behaviour (UB).
1
2
3
char buf[3] = {'A', 'B', 'C'};
std::string str = buf; // UB
std::cout << buf; // Also UB 


And I cannot do this:
void* intAddress = ptrArray; //doesn't give address, because legacy needs this format for whole c-style string...it is just the way it is!

That code should work. It should compile. You won't be able to do much with the void* though. You can print it and cast it back to a char* but not much more.

But I can still do it this way:
void* intAddress = (unsigned int*)ptrArray; //NO OVERLOADING!

You can but I'm not sure you're allowed to. There are very strict rules about what type of pointers can point to which type of data. Maybe it's OK if you don't dereference the pointer but generally you're not allowed to read an object using a pointer or reference other than the original type of the object. There are some exceptions but I don't think this is one of them.

1) Interesting that I can cast to many types and it still works, probably because all these pointers are all 8 bytes and all can hold an address.

Just because you can doesn't mean you're allowed to or that it is guaranteed to work. You need to be careful and know the rules. There are many pitfalls.

2) To get address of a particular index I used "(unsigned int*)(ptrArray+i)".

I still think you should use void*.

3) At the bottom of the code you cannot even get the address of a single char "&charK"

You can but trying to print that pointer with std::cout<< is UB because it doesn't point to a char in a null-terminated array.

and I tried (unsigned int*)charK that Gives [Warning] cast to pointer from integer of different size [-Wint-to-pointer-cast]. So it needs cast to a wide int, never did that type yet.

Did you forget the & operator?

Remember I said char is an integer type. You're essentially trying to interpret the integer value that is stored in charK as a memory address. 'k' is typically 107 so that cast will essentially give you an int pointer to the memory location 107 (technically I believe this might be UB because there is probably no int stored at that location).

Last edited on
Because it knows the first address, but returns the whole c-style string because of the need to support legacy C and convenience.

A pointer does not know "first address". A pointer has "an address".

The address could be of one object (and we have no idea what is before and after that memory location), of (some) element of array, or of something that we really should not dereference. Finally, the pointer can hold nullptr as value to indicate that it does not point to any valid address. That is all we know about the address.

That is, pointer has an address or is clearly invalid.

If we claim that the address contains a char and hand the address to function that is written to operate on C-string, then the function will do so. If the address is not into a C-string, then you get UB.
Thanks so much for everyone's help.
Oh, okay it makes even more sense now and tidies things up. So ptrArray is like any other pointer (other than it works on c-style null terminated chars/strings) and the implicit conversion stores the address of the first index in the pointer memory location "has the address".
 
char* ptrArray = myCharArray;


I thought there was something inherently different about ptrArray, but I now see that even the string class is overloaded too.
1
2
string strHello = ptrArray;
cout << "strHello = " << strHello << endl;		//"Hello World" 


Yes, I omitted the address printout of the null terminator on purpose to practice stopping before the null.
Yes, adding the & works below and it makes sense. "&charK" still has the address, but cout treats it like a char* and so we have to cast it.
1
2
3
4
5
	char charK = 'k';
	cout << charK << endl << endl;		//prints "k"
	cout << &charK << endl << endl;     //does not work...no address, prints "k"
	cout << (void*)&charK << endl; 	
	cout << static_cast<void*>(&charK) << endl;


Do you guys remember when you first started, did you have trouble with these c++ pitfalls and nuances, as I am sure there must be more.
I did end up in C++ because I was too lazy to do C. The type that Linus Torvalds did refer to when he explained why Linux kernel is written in C.

I now see that even the string class is overloaded too.
1
2
string strHello = ptrArray;
cout << "strHello = " << strHello << endl;		//"Hello World"  
1
2
3
4
5
6
7
string strHello = ptrArray;
// does use the constructor: string(const char* s);
// see: http://www.cplusplus.com/reference/string/string/string/
 
cout << strHello;
// does use ostream& operator<< (ostream& os, const string& str);
// see: http://www.cplusplus.com/reference/string/string/operator%3C%3C/ 
Do you guys remember when you first started, did you have trouble with these c++ pitfalls and nuances

I first began self-teaching myself C++ well before C++03 was available, let alone C++11 or later.

Using an antiquated copy of Visual Studio 6.0 that violated a lot of C++ rules, such as scoping variables. Ah, good times.

The next compiler/IDE I used was Borland's C++Builder, IIRC version 5, maybe 6. Better when it came to following C++ rules, but a pain trying to do simple console-mode programs.

Orwell's fork of Dev-C++ and Code::Blocks followed, Visual Studio was still a very pricey paid proposition at the time. Yes, there were the express editions, but after my experience with VS 6 not being fully C++ compliant I didn't want to waste my time or HD space.

Then VS 2015 was released, and now VS is my main to-go compiler/IDE. I know I need to learn how to do command-line compiling, but there is so much about C++ I need to get comfortable with first. I do like very much being able to write/edit source code, compile and test as I go, with the ability to debug if needed all from a single interface.

Each new standard revision has been a tough row to hoe for me, learning new ways to do things on my own.

I certainly can't say I'm an expert on C++, far from it. There are parts of the C++ standard library I still haven't learned as well as I'd like no matter what the standard version is.

I do what I can, knowing there are more knowledgeable programmers here who I can learn from the finer points of making C++ sing.

I prefer to USE the tools C++ has to offer, instead of writing my own imperfect solutions for a class grade.
Last edited on

Do you guys remember when you first started, did you have trouble with these c++ pitfalls and nuances, as I am sure there must be more.


There are far too many of them.
Yes and no, I guess. Before the internet, your resources for finding a fix to a bug caused by valid but incorrect syntax for obscure issues were nil -- you had your peers, and your books. You were luck if a peer was good enough to spot the problem. You were lucky if the books covered it.
But there were fewer of these issues back then too; the language has grown, easily doubled and maybe tripled its size, since then. There were no vectors, smart pointers, or algorithms (beyond Cs sort). Templates were an oddity you could use but probably would avoid.

Now we have the internet, and good thing too as there are too many weird issues to run down without some help for even experienced coders.

In a lot of ways, its better. We no longer have to deal with pointers everywhere or hand-rolled sorts and searches and such that are either inefficient or bugged up due to that sort of thing being invariably delegated to the nearest intern. Gone too are having to study data for a day or two to cook up a hash function for it. In some ways, it worse: we have at least 3 different but intertwined string types (string, stringstream, stringview) that make one of the most simple things going into a mashup of whatever was handy. And a lot of crap is gone or going; we no longer see union hacks and most professionals have finally weaned off C strings.

Compilers are a big help too. Back then, you did not get a warning for legal code like putting a ; on an if statement or incorrect indention that hid something that was hiding outside its loop or condition by mistake. You get warned about all sorts of common errors now -- stuff that is perfectly legal to do but usually an indication of totally wrong code.

All in all, its a lot better, but even so, there are a good dozen things to remember -- stupid stuff like getline & cin interactions, which I stumble over even now because 95% of my real coding is done in a GUI where cin and getline are distant memories...
Topic archived. No new replies allowed.
Pages: 12