c++ pointer/array distinction - c++

I am practicing for a c++ midterm, and I can't see why the following code is incorrect.
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; ++i, ++ip)
cout << *ip;
My suspicion is that is it something to do with the -5, but I'm lost, and I'd really like to get this resolved.

You cannot increase ip, since it is an array, and not a pointer - so its value [ip] is fixed.
So, the problem is with the expression ++ip

The error is that you can't increment the value of a static pointer, aka an array.
The easy solution is to simply use the indexing operator [].
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; i++)
cout << ip[i];

You can access these elements directly by using index:
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; ++i)
cout << ip[i];
or if you want to use pointer arithmetic for this purpose, you could use temporary variable - pointer that will point to first element of this array:
int ip[] = {6, 7, 2, 4, -5};
int* myPtr = ip;
for (int i = 0; i < 5; ++i, ++myPtr)
cout << *myPtr;
Note that int* myPtr = ip; is equal to int* myPtr = &ip[0].

The reason for this is:
when it comes to an array ip[],ip is pointing to the first element
of array and it is fixed and it cannot be changed(it is like a
constant pointer i.e pointing to a fixed memory location.)
2.so when you are incrementing it you are violating the condition that's why you are getting an error
try this instead
int ip[] = {6, 7, 2, 4, -5};
for (int i = 0; i < 5; ++i)
cout << ip[i];

ip is a static array.. you cannot increase it!
eventually you can create another pointer that points to ip:
int* p = ip;
then increment p.

you need to increase each value of the array ip[] separately

Pointers and arrays are distinct things.
Pointers decay to arrays, but it doesn't work the other way around.
The operator++ is not defined on arrays, so ip decays to a pointer, the pointer (unnamed temporary) is incremented, but you can't store it back into ip, because ip is an array.
The code below should work, as you expect.
#include <iostream>
int main(){
int ip[] = {6, 7, 2, 4, -5};
int *p=ip;
for (int i = 0; i < 5; ++i, ++p)
std::cout << *p;
}

Just to formalize somewhat what others are saying: ip is an array, not
a pointer. It converts implicitly to a pointer, but the results of an
implicit conversion are an rvalue, and the ++ operator requires an
lvalue. Other than the implicit conversion (which doesn't occur in all
contexts), there is no real relationship between arrays and pointers.
Note too that in C++, [] is not defined for array types, only for
pointers (or for types with user defined overloads). It only works with
arrays because of the implicit conversion.

Related

Is there any way to delete a dynamically allocated array in another function?

I am learning pointers in C++. This is the exercise given by my teacher:
6. Duplicate a given array.
int* copyArray(int* arr, int n)
My function:
int* copyArray(int* arr, int n)
{
int* copy = new int[n];
for (int i = 0; i < n; ++i)
copy[i] = arr[i];
return copy;
}
My main function:
int main()
{
int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 };
int* copyPtr = new int[8];
copyPtr = copyArray(a, 8);
for (int i = 0; i < 8; ++i)
cout << copyPtr[i] << " ";
delete[] copyPtr;
}
Is there any way that I can delete copy array from the main function? I understand the use of smart pointers but I cant use it in this case because of the prototype given by my teacher.
My suspicion is that you are confused by the usual imprecision when we say "delete a pointer". More correct would be to say delete[] x deletes the array that x points to.
In main you do
copyPtr = copyArray(a, 8);
Now copyPtr does point to the copy of the array. When you write
delete[] copyPtr;
You delete the copy of the array.
What you miss is to delete the initial array you created via int* copyPtr = new int[8]; and because you lost any pointer to it you cannot delete it anymore. You could keep the pointer to that initial array and delete it as well. Though, there is no point in allocating an array just to throw it away and create a new array inside the function. Change your code to
int main()
{
int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 };
int* copyPtr = copyArray(a, 8);
for (int i = 0; i < 8; ++i)
cout << copyPtr[i] << " ";
delete[] copyPtr;
}
PS:
I understand the use of smart pointers but I cant use it in this case because of the prototype given by my teacher.
Your conclusion is not right. Smartpointers can interoperate with raw pointers quite well. You just need to take care with ownership. int* arr is passed as raw pointer. Thats completely fine, because the function does not participate in ownership of that array. It merely reads its values. Raw pointers are for non-owning pointers. If you want to take ownership of the returned pointer you can use a std::unique_ptr<int[]>:
int main()
{
int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 };
auto copy = std::unique_ptr<int[]>(copyArray(a,8));
for (int i = 0; i < 8; ++i) std::cout << copy[i] << " ";
// no delete !!! the unique_ptr does that for you
}

How to safely insert an element into an array c++?

I have a simple program to add an element to an array:
void printArray(int inp[], int size)
{
cout << "[";
for (int i = 0; i < size - 1; i++)
{
cout << inp[i] << ", ";
}
cout << inp[size - 1] << "]" << endl;
}
int addElement(int inputArray[], int inputSize, int element, int atIndex)
{
int cur = inputSize;
while (cur >= 0)
{
if (cur == atIndex)
{
inputArray[cur] = element;
return inputSize + 1;
}
inputArray[cur] = inputArray[cur - 1];
cur--;
}
return inputSize + 1;
}
int arr1[] = {1, 5, 9, 2};
int arr2[] = {1, 5, 9, 2};
int main()
{
int arraySize = sizeof(arr1) / sizeof(arr1[0]);
addElement(arr1, arraySize, 7, 0);
printArray(arr1, arraySize + 1);
printArray(arr2, arraySize);
return 0;
}
This outputs:
[7, 1, 5, 9, 2] [2, 5, 9, 2]
Even though I haven't touched arr2 it is modified. I think because arr1 and arr2 are allocated contiguously in memory, and naively adding an element to arr1 overwrites arr2[0].
How should I handle this case and add only if the next space is unused, otherwise move the entire array to another location?
You can achieve this easily by using std::vector.
It has a method called insert, where you just pass a position and a number as arguments and it will handle the reallocation by itself.
For example: if you write:
vector<int> vec = { 1, 2, 3, 4, 5 };
vec.insert(vec.begin() + 2, 100);
Now elements in your vector are 1, 2, 100, 3, 4, 5.
I don't know if this will help you, but you can also add multiple elements at once:
vector<int> vec = { 1, 2, 3, 4, 5 };
vec.insert(vec.begin() + 3, { 100, 101 });
Now elements in your vector are: 1, 2, 3, 100, 101, 4, 5.
As you can see, the first argument is the position of the first inserted element and the second one is element or list of elements that you want to insert.
You can read more about std::vector here and about std::vector::insert here
Hope this helps.
As what the comments mentioned by #StoryTeller, you can use a std::vector.
But you have to pick on which function of the container you wanna use, there are 2 types.
::insert, which inserts data on the specific location in the
container. This is iterator based.
::push_back, which inserts at the back/last of the container
You can use any of them, depending on your purpose, just be sure of ::insert that you are pointing to the correct position(iterator wise).
Also, as of C++11 you can use ::emplace and ::emplace_back, which constructs and inserts data. You can find more at,
http://www.cplusplus.com/reference/vector/vector/
Hope this helps.
I have a simple program to add an element to an array:
Impossible. An array's size is fixed at compile time. In other words,
int arr1[] = {1, 5, 9, 2};
is a lot like:
int arr1_1 = 1;
int arr1_2 = 5;
int arr1_3 = 9;
int arr1_4 = 2;
I think it is helpful, for learning purposes, to view an array like this, and not like a container which can shrink and grow while the program is running. Adding an element to an array at runtime would be like asking to add a variable at runtime. C++ arrays don't work like that.
You can use new[] to set an array's initial size at runtime, but even then you cannot "add" anything. In fact, don't use new[], ever.
Go to cppreference.com, learn about std::vector and relearn everything from scratch. Start with the example code at the bottom of the page.

Iterating over multi-dimensional arrays

Suppose I want to do something for every number in a multi-dimensional array. I've found that you can get a pointer for the first number and then use use pointer addition. For example, the following code prints the numbers 1 through 12:
double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
double *p = &a[0][0][0];
for (int i = 0; i < 12; i++)
cout << *(p + i) << endl;
Is it unidiomatic to consider a multi-dimensional array as being flat in this way? If so, what is the preferred way of doing it? Also, is there a simpler way to write double *p = &a[0][0][0]; to get a pointer for the first number in a multi-dimensional array (in the same way that you can just write double *p = a; for a one-dimensional array)?
Yes, a multidimensional array is guaranteed to be flat. However, it may be best to kind this sort of thing. If you want to flatwise iterate over a multidimensional array, I think it'd be better to introduce a range view into it:
template <typename T>
struct Flat {
auto begin() { return first(arr); }
auto end() {
return begin() + sizeof(arr)/sizeof(*begin());
}
template <typename X> X* first(X& val) { return &val; }
template <typename X, size_t N> auto first(X(&val)[N]) { return first(*val); }
T& arr;
};
template <typename T>
Flat<T> flatten(T& arr) {
return Flat<T>{arr};
}
And simply use that one:
for (double d : flatten(a)) {
std::cout << d << std::endl;
}
Otherwise, the only other way of declaring p is something like double *p = &***a; I'm not sure if becoming a three star programmer is high on your life achievement list.
While it can be very useful to know that a multidimensional array is actually flat, it would usually be unidiomatic to refer to it using pointers and pointer arithmetic, because it introduces more potential for error and is harder to read than the idiomatic solution, subscript notation. Because of that, I would recommend using this:
double a[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 2; k++)
{
cout << a[i][j][k] << endl;
}
}
}
Yes, a multi-dimensional array can always be treated as flat. Also, same as a one dimensional array you can say double *p = reinterpret_cast<double*>(a) which is the same as double *p = &a[0][0][0].
A multi-dimensional array, if dynamically allocated, may not be flat. But then that would be obvious as the allocation will be done by you.

How to get column of a multidimensional array in C/C++?

int matrix[9][9],*p;
p=matrix[0];
this works and gives first row of matrix, but how to get first column of matrix I've tried p=matrix[][0]; ? Also I don't understand why below code gets compiler error ?
int matrix[9][9],p[9]; // it looks really ugly, byt why it doesn't work ?
p=matrix[0]; // compiler gives "invalid array assigment"
is it because multidimensional arrays are arrays of arrays - and we should interpret matrix[i][j] as j-th element of i-th nested array ?
In C/C++, multidimensional arrays are actually stored as one dimensional arrays (in the memory). Your 2D matrix is stored as a one dimensional array with row-first ordering. That is why getting a column out of it is not easy, and not provided by default. There is no contiguous array in the memory that you can get a pointer to which represents a column of a multidimensional array. See below:
When you do p=matrix[0], you are just getting the pointer to the first element matrix[0][0], and that makes you think that you got the pointer to first row. Actually, it is a pointer to the entire contiguous array that holds matrix, as follows:
matrix[0][0]
matrix[0][1]
matrix[0][2]
.
.
matrix[1][0]
matrix[1][1]
matrix[1][2]
.
.
matrix[8][0]
matrix[8][1]
matrix[8][2]
.
.
matrix[8][8]
As seen above, the elements of any given column are separated by other elements in the corresponding rows.
So, as a side note, with pointer p, you can walk through the entire 81 elements of your matrix if you wanted to.
You can get the first column using a loop like
for(int i = 0; i < 9; i++)
{
printf("Element %d: %d", i, matrix[i][0]);
}
I think the assignment doesn't work properly because you're trying to assign something's that's not an address to a pointer.
(Sorry this is c code)
There is no difference between specifying matrix[81] or matrix[9][9]
matrix[r][c] simply means the same as matrix[9*r+c]
There are other containers better suited fort multidimensional arrays like boost::multi_array
http://www.boost.org/doc/libs/1_53_0/libs/multi_array/doc/index.html
Think of the bare array just like allocating a contiguous piece of memory. You, the programmer then has to handle this piece of memory yourself. The bare name of the array, e.g. matrix is a pointer to the first element of this allocated piece of memory. Then *(matrix+1) is the same as matrix[0][1] or matrix[1].
p is an array of int, matrix[0] is a pointer..
matrix itself is the nearest thing you can get to a column of the array, inasmuch as (matrix + 1)[0][0] is the same as matrix[1][0].
Here's a program which builds a 10x10 array and prints the second column:
#include <iostream>
using namespace std;
int main()
{
int aa[10][10];
for(int i = 0; i<10; i++)
for(int j = 0; j<10; j++)
aa[i][j] = i*10+j;
int col = 2;
// pointer to a length-10 1d array
int (*p)[10] = (int (*)[10])&(aa[0][col]);
for(int i =0; i<10; i++)
cout << *(p[i]) << endl;
return 0;
}
The difference from aa[row][2] is using a pointer to a length-10 1d int array int (*p)[10], For more context about int (*p)[10], see this answer
p saves the address of 1d array {2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
. And p+1 saves the address of 1d array {12, 13, 14, 15, 16, 17, 18, 19, 20, 21}. *(p[1]) or *(*(p+1)) access the first value of 1d array.
If you want your matrix to contiguous locations, declare it as a one dimensional array and perform the row and column calculations yourself:
int contiguous_matrix[81];
int& location(int row, int column)
{
return contiguous_matrix[row * 9 + column];
}
You can also iterate over each column of a row:
typedef void (*Function_Pointer)(int&);
void Column_Iteration(Function_Pointer p_func, int row)
{
row = row * MAXIMUM_COLUMNS;
for (unsigned int column = 0; column < 9; ++column)
{
p_func(contiguous_matrix[row + column]);
}
}
For static declared arrays you can access them like continuous 1D array, p = matrix[0] will give you the 1st column of 1st row. Then the 1D array can be accessed like p[i], *(p+i), or p[current_raw * raw_size + current_column).
The things are getting tricky if a 2D array is represented with **p as it will be interpreted as an array of pointers to 1D arrays.
I don't know if this is a efficient solution but by doing this way I'm able to get the column,
int arr[9][2] = { {2, 57}, {3, 66}, {4, 73}, {5, 76}, {6, 79}, {7, 81}, {8, 90}, {9, 96}, {10, 100}};
int c[18];
int co = 0;
for (auto & i : arr) {
for (int j : i) {
c[co++] = j;
}
}
for (int i = 0; i < co; ++i) {
if (i % 2 != 0)
std::cout << c[i] << " ";
}

Iterating through C-style array not using a pointer

I am learning pointer arithmetic and have a piece of code giving me error for quite some time. any help would be appreciated.(I couldnt find it on SO)
int arr [] = {1, 2, 3, 4, 5} ;
for (int i = 0 ; i < 5 ; i++)
{
cout << *arr ;
arr++ ;
}
cout << *arr << endl ;
I am unable to understand the error i am getting in codeblocks. I am getting this statement.
error: lvalue required as increment operand|
||=== Build finished: 1 errors, 0 warnings ===|
In this code i have to iterate the array without dereferencing or using [] operator.
You are getting this error as you trying to increment the array. It is invalid because in c++, the name of the array can be implicitly converted to a constant pointer to the very first index. You cannot increment an array, because an array is a container and incrementing a container makes no sense.
To answer your question completely, I would need to explain some things. Let me try and others can add in.
Remember there are three types of constant pointers.
1.Pointer to a constant memory location.
This is a normal pointer but it points to a variable which is constant by nature (read only variable infact). It means that the value of variable it is pointing to cannot be changed through it. Normally it is used point a constant variable like this.
const int x = 10 ;
const int *ptr = & x ;
here, you cannot do *ptr = 5 ; because the pointer is pointing to a constant variable.
2.Const pointer to a memory location.
This is a pointer which can point to only one memory location throughout the program. The value of the variable it is pointing to can be changed but the pointer itself is constant. It is declared like this.
int x = 10, y = 5 ;
int * const ptr = &x ;
you cannot do ptr = &y ; later in the program. Array can be implicitly converted to a constant pointer to a memory location as well. So it cannot be incremented or decremented in this way.
(You can read about it here if you like:
What is array decaying?)
3.Constant pointer to a constant memory location.
This is a pointer which is constant itself and points to a constant memory location as well. it is declared like this.
const int x = 8 ;
const int * const ptr = &x ;
It means that neither you can point the pointer to anywhere except the initialized location, and you cannot even change the value of the location it is pointing to.
I hope the concept is very much clear by now. Now to your question: you want to print the array through pointer arithmetic, but you cannot increment the array itself. So one solution to do this is to make another pointer (a normal one) and assign it the address of the array’s first index. Then you can increment, decrement or change the value of that array. Something like this.
int arr [] = {1, 2, 3, 4, 5} ;
int *ptr = arr ;
for (int i = 0 ; i < 5 ; i++)
{
cout << *ptr << " " ;
ptr++ ;
}
So you could always do:
int arr [] = {1, 2, 3, 4, 5} ;
int *a = arr;
for (int i = 0 ; i < 5 ; i++)
{
cout << *a ;
a++ ;
}