I just started learning C++. I learned the easy way of declaring arrays and now I'm confused about the usage of
int* foo = new int[n];
and how it is different from
int foo [n];
I tried testing with code but couldn't find any difference. I read from sources that using "new" requires me to manually de-allocate the memory after I don't need it anymore. In that case, there is no advantage in using "new" or dynamic memory allocation at all. Am I missing something here?
I tried running this:
#include <iostream>
int main() {
int n;
std::cout << "array size" ;
std::cin >> n ;
std::cout << n ;
int foo [n]; //line A
// int* foo = new int[n]; //line B
foo[6] = 30;
std::cout<<foo[6]<<std::endl;
}
Commenting out line B to run line A, or vice versa, gave the exact same result.
There are several ways these are different. First, let's talk about this one:
int n = 10;
int array[n];
This is not part of the ANSI C++ standard and may not be supported by all compilers. You shouldn't count on it. Imagine this code:
int n = 10;
int array[n];
n = 20;
How big is array?
Now, this is the way you can do it (but it's still problematic):
int n = 10;
int * array = new int[n];
Now, that is legal. But you have to remember later to:
delete [] array;
array = nullptr;
Now, there are two other differences. The first one allocates space on the stack. The second allocates space on the heap, and it's persistent until you delete it (give it back). So the second one could return the array from a function, but the first one can't, as it disappears when the function exits.
HOWEVER... You are strongly, strongly discouraged from doing either. You should instead use a container class.
#include <array>
std::array<int, n> array;
The advantages of this:
It's standard and you can count on it
You don't have to remember to free it
It gives you range checking
Related
So, i was doing some harcker rank exercisies, and i found this exercise.
In short it is an Interval Schedulling problem, but my doubt is about pointers and data structure.
This code below is a simple version of my doubt.
My doubt is in the initialize function. When the program finishes it the ptr pointer variable has only one instance of arrayOfA, the first entry only and i wanted to have the size of N.
So what i did get wrong about this data structure and it`s pointers?
I don't want to use another lib as vector and stuff because i think there is no need of it.
#include <iostream>
struct A
{
unsigned int startTime;
unsigned int duration;
unsigned int endTime;
};
struct B
{
int size;
A* arrayOfA = new A[size];
};
B* initialize(int start_time[], int duration[], int n)
{
B* pointer = new B();
pointer->size = n;
for (int i = 0; i < n; i++)
{
pointer->arrayOfA[i].startTime = start_time[i];
pointer->arrayOfA[i].duration = duration[i];
pointer->arrayOfA[i].endTime = start_time[i] + duration[i];
}
return pointer;
}
int main()
{
//initialization
int n = 6;
int arrayOfStart[] = { 1, 3, 0, 5, 5, 8 };
int arrayOfDuration[] = { 1, 1, 6, 2, 4, 1 };
B* ptr;
ptr = initialize(arrayOfStart, arrayOfDuration, n);
for (int i = 0; i < n; i++)
{
std::cout << ptr->arrayOfA[i].startTime << std::endl;
}
}
I don't want to use another lib as vector and stuff because i think there is no need of it
The fact that you got this simple example wrong - and that this simple example is actually not that simple to implement correctly - is solid evidence that you are wrong.
The whole point of having standard libraries is that there is rarely a good reason to implement these things by hand, and it's easy to get them wrong. And std::vector is not "another lib", it is provided by the standard library for a reason.
the ptr pointer variable has only one instance of arrayOfA
it's only supposed to have one array. You mean, presumably, that the array is the wrong size? How did you tell? What happened when you tried to read all 6 elements?
Anyway, the immediate problem is
A* arrayOfA = new A[size];
... this should go in a constructor. You have to defer evaluation until after you know the value of size.
Then you should also write a destructor, and then you should write the copy constructor, copy assignment operator, and move equivalents.
But if you learned, and used, std::vector instead - you would have finished the problem in the time it took to debug your array handling code.
The whole point of providing libraries of common tools is that you can learn them once and re-use your knowledge. If you write your own bare array code in every hackerrank problem, you can easily encounter different bugs in each one, and you're not accumulating any knowledge you can re-use in the next.
Given this struct:
struct B
{
int size;
A* arrayOfA = new A[size];
};
a default B will have a pointer pointing to an array of size elements. Since size is not initialized, this invokes undefined behavior.
Instead, you can do:
struct B
{
int size;
A* arrayOfA;
};
and after you set the size member, you can allocate the appropriate memory:
pointer->size = n;
pointer->arrayOfA = new A[pointer->size];
Also, don't forget to delete this memory when it's no longer needed by the program.
I have the following task:
Creat a program that will transform array A to array B in the followin order:
http://gyazo.com/29e434ebdc1e235fe0fc97c26ae9fe9c
The size of A is entered by user, as well the elements. Print the new elements of B. "Use pointers"
Examples: If I input 1234567, the program will output 8888888.
Here's my code:
#include <iostream>
using namespace std;
int main()
{
int N;
cout << "Enter the size of array" << endl;
cin >> N;
int A[N], B[N];
cout << "Enter the elements of the array" << endl;
for(int i = 0; i < N; i++){
cin >> A[i];
}
for(int i = 0; i < N; i++){
B[i] = A[i] + A[N-i-1];
}
for(int i = 0; i < N; i++){
cout << B[i] << " ";
}
return 0;
}
There is only one problem I have, it says to "use pointers" but I don't know where shall I use them and they must be used... thanks in advance.
int A[N], B[N];
This code is non-standard (when N is a variable). Your compiler allows that, but if you try to compile this code in other one, it probably won't work.
Using pointers in this case means, that you should allocate memory for the arrays dynamically, eg.
int * A, * B;
A = new int[N];
B = new int[N];
This code is valid in terms of C++ standard.
Remember though, that you will have to free allocated memory manually after you don't need it anymore:
delete[] A;
delete[] B;
This should work with the rest of your code left unchanged, since [] operator works for pointers as well.
And finally, if you really are writing a C++ program, you surely should be using std::vector instead of C-style arrays...
Edit: (in response to comment)
If you declare a variable in the following way:
int * A;
And then write:
cin >> *(A + i);
It means:
Read data from user and parse it;
Go i "steps" starting from address A (it actually "walks" i * sizeof(*A) bytes from A).
Put the data read from the user to memory pointed to by place evaluated in step 2.
But when you declare:
int (*A)[N];
The A becames pointer to the array of N elements. Since array is convertible to a pointer to its first element, you may think of that previous line (for the sake of explanation) as
int ** A;
In such case compiler tries to do the same as I described earlier. But now it walks i pointers starting from A, not *int*s. Then it dereferences that pointer getting an int * and attempts to put there data written by user. But >> operator of cin is not able to translate text to a pointer and that's why compiler complains.
Foot note
While you're learning using pointers, you may think of <something> variable[] as being equal to <something> * variable pointing to the first element of that array. This is a lie (because array is not a pointer, but it's convertible to a pointer to its first element), but helps understanding what arrays do have in common with pointers. That's why you can think of
int (* A)[];
As a
int ** A;
Well, this
cin >> N;
int A[N], B[N];
is not valid ANSI C++. You cannot declare arrays with variable indices. So you need a way to declare variable length arrays, and one way is to use pointers and dynamically allocated memory using new[] (and then delete[]).
The other, preferable method would be to use a container such as std::vector.
I want to do something like this below:
int main() {
int a[10];
int *d = generateArrayOfSize(10) // This generates an array of size 10 on the heap
a = d;
print(a); // Prints the first 10 elements of array.
}
However above code gives compilation error (incompatible types in assignment of ‘int*’ to ‘int [10]’).
What can I do to make the above code to work?
Arrays are non-assignable and non-copyable, so you'd have to copy each element by hand (in a loop), or using std::copy.
If you're using C++, then use C++ arrays rather than C style arrays and pointers. Here's an example
#include <array>
#include <iostream>
template<size_t N>
std::array<int, N> generateArrayOfSize(void)
{
std::array<int, N> a;
for (int n=0; n<N; ++n)
a[n] = n;
return a;
}
template<size_t N>
void print(std::array<int, N> const &a)
{
for (auto num : a)
std::cout << num << " ";
}
int main() {
std::array<int, 10> a;
std::array<int, 10> d = generateArrayOfSize<10>();
a = d;
print(a); // Prints the first 10 elements of array.
}
which outputs 0 1 2 3 4 5 6 7 8 9
Arrays are not pointers.
You can't do :
int a[10];
int *d;
a = d;
Change it to :
int *a;
int *d;
a = d;
Main differences between arrays and pointers in C programming :
Pointer | Array
-------------------------------------------|-------------------------------------------
A pointer is a place in memory that keeps | An array is a single, pre allocated chunk
address of another place inside | of contiguous elements (all of the same
| type), fixed in size and location.
-------------------------------------------|-------------------------------------------
A pointer can point to a dynamically | They are static in nature. Once memory is
allocated memory. In this case, the memory | allocated , it cannot be resized or freed
allocation can be resized or freed later. | dynamically.
-------------------------------------------|-------------------------------------------
You have a quite good explanation here : https://stackoverflow.com/a/7725410/1394283
An array is not a pointer (although a name of an array often decays to a pointer to its first element).
To make the above code to work, you can declare a as a pointer: int *a;. The print function takes an int* (or a decayed array) anyway.
If you really want to have two arrays and copy contents from one array to another, you should copy the data in a loop.
This will print in this way when you assign a string reference to a pointer you have to use *ptr to print the value of a pointer otherwise in your case print(d) that is like cout< in c++ it will only print the location of the d[0].
int ary[5]={1,2,3,4,5};
int *d;
d=ary;
for(int i=0;i<5;i++)
cout<<*(d+i);
Because array names are non-modifiable. So you can't do
a = d;
Declare it as a pointer like this:
int *a;
Little rusty with my C++ but try something like this.
int main() {
int *a;
int *d = generateArrayOfSize(10) // This generates an array of size 10 on the heap
a = d;
print(a); // Prints the first 10 elements of array.
}
In C, it was always true when Thing X[10]; was declared, X was the constant address of the first element(i.e. &X[0]). So you could then say:
Thing *Y = X; // Equivalent to (Thing *Y = &X[0];)
But in C++, the compiler "remembers" that the Thing array X has 10 elements, and some C++ imposed type checking rules break. Imagine we add Thing Z[20]; to the discussion.
Thing *Y = X; and Thing *Y = Z; if both allowed, would imply that a single variable could be set to Thing Arrays of length 10 and 20, which are very different (ahem) "things", as a quick look at a 2D array will reveal. This sort of justifies why the C language assumed equivalent of X and &X[0] is broken in C++.
Well, at least for some versions of C++. So best not to assume it, and use
Thing *Y = &x[0]; and Thing *Y = &Z[0] instead;
This approach has two advantages. It does what is wanted, and it actually compiles. :-)
I'm currently learning C++, so sorry if I seem a little silly.
My current exercise, that I'm stuck on, requires me to write a function, IndexArray(int n) that returns a pointer to a dynamically allocated integer array with n elements, each of which is initialised to its own index.
(copied from the worksheet).
I've read this several times and don't fully understand it, but they gave an example:
Assuming that intPtr is declared as
int *intPtr;
the statement
intPtr = IndexArray(10);
should produce the following memory configuration:
intPtr -> 0 1 2 3 4 5 6 7 8 9
From this example I'm guessing my function needs to create an array of size n, with values from 0 to n-1, and then another pointer needs to point to that array.
Here's their test code:
int *values1;
values1 = IndexArray(10);
I know how to easily create the array, but I don't fully understand pointers enough to know really what to do. I figured returning an array would work:
int *IndexArray(int n) {
cout << n << endl;
int arrayTemp[n];
for(int i = 0; i < n; i++) {
arrayTemp[i] = i;
}
return arrayTemp;
}
However when tested, values1 array doesn't contain the values from 0-9 (although arrayTemp does right before it's returned).
Any help would be amazing, and hopefully I've given everything you need to help. Thanks! :D
int arrayTemp[n];
Notice that the statement is in a function, so when the function terminates, the arrayTemp[] will not be available any more, it coule be removed : it is a #local# variable!
So, if you want to do that , you could use :
int * arrayTemp = new int[n];
NOTICE : you must delete it any how to avoid memory leaks.
You cannot do this:
int *IndexArray(int n) {
cout << n << endl;
int arrayTemp[n]; //declare a local array
for(int i = 0; i < n; i++) {
arrayTemp[i] = i;
}
return arrayTemp; //return a pointer to a local
}
You cannot return a pointer to a local. The local ceases to exist once you return. The pointer now points to garbage.
Instead, you have to use malloc (C or C++) or new (C++) to dynamically create storage for 10 ints, and since this is dynamically created on the heap it will persist after returning (and will need to be freed if malloced or delete[]d if it was a an array made with new. For just single objects made with new you just use delete )
I'am wondering if built-in types in objects created on heap with new will be initialized to zero? Is it mandated by the standard or is it compiler specific?
Given the following code:
#include <iostream>
using namespace std;
struct test
{
int _tab[1024];
};
int main()
{
test *p(new test);
for (int i = 0; i < 1024; i++)
{
cout << p->_tab[i] << endl;
}
delete p;
return 0;
}
When run, it prints all zeros.
You can choose whether you want default-initialisation, which leaves fundamental types (and POD types in general) uninitialised, or value-initialisation, which zero-initialises fundamental (and POD) types.
int * garbage = new int[10]; // No initialisation
int * zero = new int[10](); // Initialised to zero.
This is defined by the standard.
No, if you do something like this:
int *p = new int;
or
char *p = new char[20]; // array of 20 bytes
or
struct Point { int x; int y; };
Point *p = new Point;
then the memory pointed to by p will have indeterminate/uninitialized values.
However, if you do something like this:
std::string *pstring = new std::string();
Then you can be assured that the string will have been initialized as an empty string, but that is because of how class constructors work, not because of any guarantees about heap allocation.
It's not mandated by the standard. The memory for the primitive type members may contain any value that was last left in memory.
Some compilers I guess may choose to initialize the bytes. Many do in debug builds of code. They assign some known byte sequence to give you a hint when debugging that the memory wasn't initialized by your program code.
Using calloc will return bytes initialized to 0, but that's not standard-specific. calloc as been around since C along with malloc. However, you will pay a run-time overhead for using calloc.
The advice given previously about using the std::string is quite sound, because after all, you're using the std, and getting the benefits of class construction/destruction behaviour. In other words, the less you have to worry about, like initialization of data, the less that can go wrong.