(Disclaimer: Pointers in C++ is a VERY popular topic and so I'm compelled to believe that someone before me has already raised this point. However, I wasn't able to find another reference. Please correct me and feel free to close this thread if I'm wrong.)
I've come across lots of examples that distinguish between pointer to first element of array and pointer to the array itself. Here's one program and its output:
//pointers to arrays
#include <iostream>
using namespace std;
int main() {
int arr[10] = {};
int *p_start = arr;
int (*p_whole)[10] = &arr;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
cout << "Adding 1 to both . . . " <<endl;
p_start += 1;
p_whole += 1;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
return 0;
}
Output:
p_start is 0x7ffc5b5c5470
P_whole is 0x7ffc5b5c5470
Adding 1 to both . . .
p_start is 0x7ffc5b5c5474
P_whole is 0x7ffc5b5c5498
So, as expected, adding 1 to both gives different results. But I'm at a loss to see a practical use for something like p_whole. Once I have the address of the entire array-block, which can be obtained using arr as well, what can I do with such a pointer?
For single arrays, I don't think there's much point to it. Where it becomes useful is with multi-dimensional arrays, which are arrays of arrays. A pointer to one of the sub-arrays is a pointer to the row, and incrementing it gets you a pointer to the next row. In contrast, a pointer to the first element of the inner array is a pointer to a single element, and incrementing it gets you the next element.
int (*)[10] is a "stronger" type than int* as it keeps size of the array,
so you may pass it to function without passing additional size parameter:
void display(const int(*a)[10]) // const int (&a)[10] seems better here
{
for (int e : *a) {
std::cout << " " << e;
}
}
versus
void display(const int* a, std::size_t size) // or const int* end/last
{
for (std::size_t i = 0; i != size; ++i) {
std::cout << " " << a[i];
}
}
Related
When using the address transfer of function, View address blocks of formal parameters and actual parameters, I find that the arguments and formal parameters of array share one address block, while the arguments and formal parameters of variables use two address block. What is the reason?
The code is as follows:
#include<iostream>
using namespace std;
void test(int *i,int * arr) {
cout << &i << endl;
cout << arr << endl;
}
int main() {
int i = 1, arr[2] = {1,2};
cout << &i << endl;
test(&i, arr);
cout << arr << endl;
system("pause");
return 0;
}
And this is the output:
0000008986B6FC54
0000008986B6FC30
0000008986B6FC78 //Arrays use the same space
0000008986B6FC78
You are passing pointers to the functions. The value of the pointers are not modified, ie in the function they point to the same objects as they do in main.
However, you are not printing what you think you print:
void test(int *i,int * arr) {
cout << &i << endl;
cout << arr << endl;
}
The pointer i gets the parameter &i (the i from main). Hence printing i in main will yield the same value as printing i in test. However, you are printing the adress of i in the function not the value of it. If you change your code to:
void test(int *i,int * arr) {
cout << &i << endl;
cout << i << endl;
cout << arr << endl;
}
You will notice the difference. I suggest you to rename at least one of the is in your code, because using same name for different entities can and does cause confusion. The i in test holds the value of the address of the i in main. That does not mean that they are the same, but rather i in test has the same value as &i in main.
In short: &i == &i but you expect &(&i) to be the same as &i.
There is no difference between passing a pointer to the int or passing a pointer to the first element of the array. From the point of view of the function they are both just pointers to int.
Note that test prints the value of arr but the location of i.
In test, &i is the location of its argument i.
That argument's value is the location of the i in main.
You will see this if you print i instead of &i.
arr, on the other hand, is implicitly converted into a pointer to its first element, and you are both passing &arr[0] to test to print, and printing &arr[0] in main.
Here is the same thing with explicit conversions and without using a function:
int main() {
int i = 1, arr[2] = {1,2};
cout << &i << endl;
// Create the "argument"...
int *p = &i;
// These two lines are 'test'...
cout << &p << endl;
cout << &arr[0] << endl;
// and this is after the function call.
cout << &arr[0] << endl;
}
I need to print an array by implementing the use of a function before the main function. So I tried the following function:
int* printArr(int* arr)
{
for (int i = 0; i < 5; i++) {
cout << arr[i];
}
return arr;
}
I encountered two problems when implementing this into the whole code.
First, this is printing what I think is the address of the array and not the actual array. Pretty sure this is because of the return arr; in line 10. But if I do not write return then the code will produce an error. How can I fix this?
Second, I do not understand the second argument printArr has. In line 19, you can see cout << printArr(arr, 5) << endl;. How come there is a single numeric value, that one being 5 in this case, as an argument? How can I account for this in my function?
Please keep in mind that I am new to C++ and coding in general. Also, this code was given to me, hence why I do not understand certain aspects of it.
This is my code so you can see what I mean:
#include <iostream>
using namespace std;
// Declare function printArr here
int* printArr(int* arr)
{
for (int i = 0; i < 5; i++)
{cout << arr[i];}
return arr;
}
int main()
{
int arr[5] = {1, 3, 5, 7,9};
int last_num = arr[sizeof(arr)/sizeof(int)-1];
cout << "Before reversing" << endl;
cout << printArr(arr, 5) << endl;
// reverse "arr" using reference(&)
cout << "After reversing" << endl;
printArr(arr, 5);
return 0;
}
The declaration and implementation of printArr() is all wrong.
First, this is printing what I think is the address of the array and not the actual array.
The printArr() function itself is printing the contents of the array (well, the first 5 elements anyway), and then returning the address of the array. It is main() that is printing that address afterwards, when it passes the return value of printArr() to std::cout <<.
Pretty sure this is because of the return arr; in line 10. But if I do not write return then the code will produce an error. How can I fix this?
By getting rid of the return type altogether. There is no good reason to return the array pointer at all in this example, let alone to pass that pointer to std::cout. So printArr() should be returning void, ie nothing.
Second, I do not understand the second argument printArr has. In line 19, you can see cout << printArr(arr, 5) << endl;. How come there is a single numeric value, that one being 5 in this case, as an argument?
Because main() is passing in the element count of the array (5) so that printArr() can know how many elements to actually print, instead of hard-coding that value in the loop. However, your declaration of printArr() does not have a 2nd parameter with which to accept that value, that is why you are getting errors.
How can I account for this in my function?
By adding a 2nd parameter in the function declaration, eg:
#include <iostream>
using namespace std;
// Declare function printArr here
void printArr(int* arr, int size)
{
for (int i = 0; i < size; i++)
{
cout << arr[i] << ' ';
}
cout << endl;
}
int main()
{
int arr[5] = {1, 3, 5, 7, 9};
const int count = sizeof(arr)/sizeof(arr[0]);
int last_num = arr[count-1];
cout << "Before reversing" << endl;
printArr(arr, count);
// reverse "arr" using reference(&)
cout << "After reversing" << endl;
printArr(arr, count);
return 0;
}
Live Demo
Before my program can free up memory and end it crashes. Crashes seem to happen on transition from the function UserDataCollection and back to main. This is only my second program using pointers so I'm still quite the newbie considering the whole point of c++ is to use pointers.
Here is the aforementioned code:
#include <iostream>
//Prototypes
void UserDataCollection(int * &movieData_ptr, int &numSurveyed); // Movie Statistics
void DisplayOutput(int *movieData_ptr, int numSurveyed); //Mean, Median, Mode (Display To Console)
//Global Constants
int main()
{
//Variables
int numSurveyed = 0;
//Pointers
int * movieData_ptr = nullptr;
movieData_ptr = new int[numSurveyed];
//"Program Start"
std::cout << "Program start...\n\n";
UserDataCollection(movieData_ptr, numSurveyed);
DisplayOutput(movieData_ptr, numSurveyed);
//Release Memory
delete[] movieData_ptr;
std::cout << "Memory Cleared.";
return 0;
}
void UserDataCollection(int * &movieData_ptr, int &numSurveyed)
{
//Get Number of Students Surveyed
std::cout << "How many students were surveyed: ";
std::cin >> numSurveyed;
//Student Data Input Loop
for (int i = 0; i < numSurveyed; i++)
{
//Get Student Data
std::cout << "Enter How many movies student " << i + 1 << " has seen in ONE month: ";
std::cin >> *(movieData_ptr + i);
//Validation Check
while (*(movieData_ptr + i) >= 337)
{
std::cout << "\nImpossible value!" << std::endl
<< "Hours in a month: 730. Average movie length: 130 minutes."
<< "Total Possible movies: 337";
std::cout << "\n\nEnter How many movies student " << i + 1 << " has seen in ONE month: ";
std::cin >> *(movieData_ptr + i);
} //end while (Validation Check)
} // end for (Data Input)
}
void DisplayOutput(int *movieData_ptr, int numSurveyed)
{
//Display loop for pointer array
for (int i = 0; i < numSurveyed; i++)
{
std::cout << *(movieData_ptr + i) << " ";
}
//End Message
std::cout << "\n\nProgram end.";
}
You never allocated any memory.
int numSurveyed = 0;
//Pointers
int * movieData_ptr = nullptr;
movieData_ptr = new int[numSurveyed];
This is the equivalent of
int *movieData_ptr = new int[0];
You are allocating size of 0 ints. This is undefined behaviour. You can't do anything useful with that pointer without a segmentation fault. You need to either pre-allocate a certain amount, and make sure you don't overflow, or dynamically allocate every time you plan to add data.
Since this is C++, it's probably better not to use raw pointers, but use vector or something instead.
Sorry:
From 5.3.4/7
When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.
From 3.7.3.1/2
The effect of dereferencing a pointer returned as a request for zero size is undefined.
So, I have been trying to learn C++ and in the tutorial book that I am reading, I have gotten stuck on a problem of pointers-to-pointers. What I am trying to do change the pointer a pointer-to-pointer is pointing to without changing the value of the original pointer. Here's some code...
#include <iostream>
void testFunc(int **func_p_to_p) {
int *createdPointer = new int(10);
*func_p_to_p = createdPointer;
cout << **func_p_to_p << endl; //prints 10 as I expect
}
int main() {
int **main_p_to_p = NULL;
int *mainPointer = new int(5);
main_p_to_p = &mainPointer;
testFunc(main_p_to_p);
cout << **test << endl;//prints 10, I expect this...
cout << *mainPointer << endl; //prints 10 as well, I don't want that.
}
I asked a similar question about this earlier, here and I understand sort of what is going on. However, I can't seem to figure out how I would change where a pointer-to-pointer is pointing to without changing the original value. Could anyone explain how I would do this? Thanks.
In the line
*func_p_to_p = createdPointer;
you first follow your pointer-pointer to what it is pointing to: The address of int *mainPointer.
Next you assign a new value to this pointer, the value of createdPointer which is the address of new int(10).
So your mainPointer is now changed to target the same memory as createdPointer. Does this make any sense to you?
You can't do that. main_p_to_p points to mainPointer, so modifying *main_p_to_p modifies mainPointer, full stop.
You might be looking for this, though:
int main() {
int **main_p_to_p = NULL;
int *mainPointer = new int(5);
int *secondPointer = mainPointer;
main_p_to_p = &secondPointer;
// prints 5 5 5
cout << *mainPointer << " " << *secondPointer << " " << **main_p_to_p << std::endl;
testFunc(main_p_to_p);
// prints 5 10 10
cout << *mainPointer << " " << *secondPointer << " " << **main_p_to_p << std::endl;
}
Note that you don't need the main_p_to_p variable, but I left it in for consistency with the question.
This may a stupid question, but I'm gonna ask it anyway:
Suppose you have a pointer: Object* pointer which points at a dynamically allocated object.
class PointClass
{
Array<Object*> m_array1;
Array<Object*> m_array2;
void Delete1()
{
for (int i = 0; i < m_array1.Length; i++)
{
delete m_array1[i];
}
}
void Delete2()
{
for (int i = 0; i < m_array2.Length; i++)
{
delete m_array2[i];
}
}
}
Now, you put your pointer both in m_array1 and in m_array2.
When you try to delete the arrays, in one of them you will have a pointer which points to a deallocated space, so you can't delete it again!
I can't just assign the pointers NULL after the deletion because it wouldn't affect the pointer in the other array.
How would you solve it?
Well the simplest way would be to use a reference-counting pointer, like those available in boost::smart_ptrs.
Otherwise, you need to assign owners to the pointers - you need to decide which class will be responsible for allocating/deleting that particular pointer. If for some reason you decide that should be this class, then you could remove the duplicates from the arrays by adding all the pointers to a set before enumerating them.
If you have to share pointers in this way, something like a ref counted pointer may work well.
See this site which gives an exposé of various 'smart-pointer' techniques.
Smart Pointers
My initial answer is: Don't do that.
If you absolutely have to for some reason, you could wrap it in a smart pointer
Best solved is not passing the same pointer to both arrays. :P If you really need to, and you also need to reflect that change to all other "same" pointers, a pointer-to-pointer will do.
#include <iostream>
struct Object{};
int main(){
Object* ptr = new Object;
Object** ptrptr = &ptr;
delete *ptrptr;
*ptrptr = 0;
// both print 0
std::cout << *ptrptr << std::endl;
std::cout << ptr << std::endl;
}
On Ideone.
Another way is with a reference-to-pointer.
int main(){
Object* ptr = new Object;
Object*& refptr = ptr;
delete refptr;
refptr = 0;
// both print 0
std::cout << refptr << std::endl;
std::cout << ptr << std::endl;
}
But the second best way is probably a ref-counted smart pointer.
How would you solve it?
By not storing the same pointer in two different places. Doing this creates a duplication of data, and confuses ownership semantics. Who owns the memory pointed to by pointer? Ownership is not clear.
Under normal circumstances, dynamically allocated objects should be owned by the same module that allocated it, and only that module will have direct access to the objects or delete the memory. That's not to say other modules can't get at the data.
As others have suggested use smart pointers to solve your problem. If you have to solve it by writing your own code, I would make each of the delete function also search the "other" array to delete all pointers in the first array that can be found in the other array. And it is a last option option as this would not be my first solution to implement anything as your approach
void Delete2()
{
for (int i = 0; i < m_array2.Length; i++)
{
for (int j = 0; j < m_array1.Length; j++)
{
if (m_array2[i] == m_array1[j])
{
delete m_array1[j]
m_array1[j] = NULL;
}
delete m_array2[i];
m_array2[i] = NULL;
}
}
Then look for ways to optimise it
If I understood your question, you have the same (valid) pointer stored in 2 different arrays.
The problem is that after you delete it on array1, you can't do it again in the second array.
One way to do this is change your array definition to store the memory address of the pointer itself, instead of storing the address of the allocated memory:
const int array_size = 3;
int** m_array1[array_size];
int** m_array2[array_size];
and the rest of the code could be implemented as:
void Delete1()
{
for (int i = 0; i < array_size - 1; i++) // delete all memory but leave the last intact
{
if (*(int*)m_array1[i])
{
cout << "Delete1: erasing #" << i << " with mem addr " << std::hex << *m_array1[i] << std::dec << endl;
delete *m_array1[i];
*m_array1[i] = NULL;
}
}
}
void Delete2()
{
for (int i = 0; i < array_size; i++)
{
if (*m_array2[i])
{
cout << "Delete2: erasing #" << i << " with mem addr " << std::hex << *m_array2[i] << std::dec << endl;
delete *m_array2[i];
*m_array2[i] = NULL;
}
else
{
cout << "Delete2: !!! memory at #" << i << " was already deleted." << endl;
}
}
}
int main()
{
int* num1 = new int(10);
int* num2 = new int(20);
int* num3 = new int(30);
cout << "main: storing " << std::hex << &num1 << " which points to " << num1 << std::dec << endl;
cout << "main: storing " << std::hex << &num2 << " which points to " << num2 << std::dec << endl;
cout << "main: storing " << std::hex << &num3 << " which points to " << num3 << std::dec << endl;
m_array1[0] = &num1;
m_array1[1] = &num2;
m_array1[2] = &num3;
m_array2[0] = &num1;
m_array2[1] = &num2;
m_array2[2] = &num3;
Delete1();
Delete2();
}
Outputs:
main: storing 0xbfc3818c which points to 0x87b6008
main: storing 0xbfc38188 which points to 0x87b6018
main: storing 0xbfc38184 which points to 0x87b6028
Delete1: erasing #0 with mem addr 0x87b6008
Delete1: erasing #1 with mem addr 0x87b6018
Delete2: !!! memory at #0 was already deleted.
Delete2: !!! memory at #1 was already deleted.
Delete2: erasing #2 with mem addr 0x87b6028