The following is a small scale example of the problem I am facing. In the example below I use int pointers but in my own code I am really using a pointer to another class (a node class).
The problem appears to be that I am using a call by value pointer (if there is such a thing). I don't know, I thought pointers were by reference. I do need to be able to pass multiple pointers to the method and I do not really want to write a specific method for each pointer. When I run the code, of course, I get some kind of error because it is trying to access a pointer that has not been allocated.
I do not understand why it would not initialize the correct pointer if I pass the specific pointer I want.
Any help would be greatly appreciated.
#include <iostream>
using namespace std;
class Test {
private:
int *p1;
int *p2;
int sizeP1;
int sizeP2;
public:
int* getIntPointer() {return p1;}
void initializeP1(int *ip,int n){
sizeP1=n;
ip=new int[n];
for(int i=0;i<n;i++)
p1[i]=i;
}
void printP1() {
for(int i=0;i<sizeP1;i++)
cout<<p1[i]<<" ";
}
};
int main() {
Test t;
t.initializeP1(t.getIntPointer(),10);
t.printP1(); //this fails.. but why? How can I fix it?
return 0;
}
The problem is that you initialize ip and you fill p1
void initializeP1(int **ip,int n){
sizeP1=n;
*ip=new int[n];
for(int i=0;i<n;i++)
*ip[i]=i;
}
//call with p1
initializeP1(&p1, 10); // pass pointer to pointer so you can get return value.
The problem is that your function allocates memory to the copy of the pointer that is the argument - this copy is lost at function exit. Pass the pointer by reference instead by changing the function signature
void initializeP1(int* &ip,int n){
^
This way the allocated memory is still accessible and your pointer will point to it
Would it not simply be easier to change your initializeP1 function to something like:
int * initializeP1(int n)
{
sizeP1 = n;
p1 = new int[n];
for(int i = 0; i < n; ++i)
p1[i] = i;
return ip;
}
There are still problems with this however, such as the fact that you can call it repeatedly and cause big memory leaks.
It might be better to use a proper constructor for your class that does what initializeP1 did, like such:
Test(int n)
{
sizeP1 = n;
p1 = new int[n];
for(int i = 0; i < n; ++i)
p1[i] = i;
return ip;
}
Pointers are not passed by reference, no. Pointers are value types. You'd want to use a reference if you absolutely had to make it look like this, but it's an abuse of syntax and you should do it a different way instead.
The call to t.getIntPointer() returns a pointer that is not initialised to something sensible.
The call to initializeP1() is newing an array of ints.
But be careful, this allocated block of memory will not be freed until you tell it so by writing "delete [] p1;".
Related
my question can be briefly shown as the following example.
void func(int n){
char *p = (char*)malloc(n);
// some codes
memset(p,0,sizeof(name));
// free(p); // Commenting this line represents that I forget to release the allocated memory.
}
int main(){
// some codes
for (int i; i < Nl; i++){
func(100);
// How can I release the allocated memory of p outside of the func?
}
}
I whish to release the allocated memory, which is allocated in a function, outside of this function.
Thank you.
The pointer in question is not returned from the function in any way, so if you don't free it in the function then the memory is leaked. You would need to modify the function to either assign the pointer to a global, return it from the function, or assign it to a dereferenced pointer passed to the function.
If your goal is to find and fix memory leaks in your program, there are tools such as valgrind which can help you with that.
To solve the problem it's better to use std::unique_ptr. If you use smart pointer it will be released whenever it's not required anymore.
Foe example :
void my_func()
{
std::unique_ptr<int> valuePtr(new int(15));
int x = 45;
// ...
if (x == 45)
return; // no memory leak anymore!
// ...
}
You can check the link to study more :
https://en.cppreference.com/book/intro/smart_pointers
Two solutions in C
a) use VLA
void foo(int n) {
char p[n];
// use p
// no need to free, p automatically releases its memory
}
b) return the pointer to the caller
char *foo(int n) {
char *p = malloc(n);
// use p
return p;
}
int main(void) {
char *bar = foo(100);
free(bar);
}
If I understand you correctly, you are struggling with the basic concept of memory management.
Looking at your code you are malloc, which is a core C memory management aspect, although you tagged the question as C and C++. I can go into depth on why there ain't a thing like C/C++, though it's better explained here: https://cor3ntin.github.io/posts/c/
One of the elements C and C++ programmers disagree is the use of malloc, which is standard in C and and only used in exceptional cases in C++.
If we look from a C++ standpoint, I'd argue you should be learning it with a recent version. Here the answer is simple: use std::make_unique:
auto p = std::make_unique<char[]>(n);
Or in this case as you are trying to do something with strings, just use std::string. Trust me, doing so will prevent a lot of grief. Let me also remark that you often don't need memory allocations, more about that can be found here: https://stackoverflow.com/a/53898150/2466431
If you however ain't programming C++, you can use malloc. Here it is important to understand that every pointer returned by malloc ends up as an argument for free. (Exceptions on this ain't for beginners)
After you call free, you can't use what the pointer points to, not the value stored in the pointer. Calling free twice for the same pointer is also an issue.
Hence, unlike in the C++ code where the memory gets freed when no longer used. You need to keep detailed attention for this and call free.
In your function, uncommenting the free is the correct solution.
If you have the intention to let the data outlive the function call, you should be returning the pointer to the caller, this is than responsible for the ownership:
char * func(int n){
char *p = (char*)malloc(n);
// some codes
memset(p,0,sizeof(name));
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
char *s = func(100);
free(s);
}
}
Let me show the same with the previously mentioned C++:
#include <memory>
std::unique_ptr<char[]> func(int n){
auto p = std::make_unique<char[]>(n);
// some codes
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
auto s = func(100);
}
}
Or using std::string
#include <string>
std::string func(int n){
auto p = std::string(n, '\0');
// some codes
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
auto s = func(100);
}
}
Why this code is working:
//Things
int **A;
main(){
//things
A = new int*[n];
for (int i = 0; i < n; i++) {
A[i] = new int[m];
}
// things
}
And this code isn't working:
//Things
int **A;
void functionOutsideMain(int **A,int n, int m){
A = new int*[n];
for (int i = 0; i < n; i++) {
A[i] = new int[m];
}
}
main(){
//Things
functionOutsideMain(A,n,m);
//Things
}
When I use new operator outside main function in a separate function it won't work.
But if I use new operator inside main funcion it works.
Can you explain me why this is happening?
or
If I'm doing something wrong.
In the first example, A is just a global variable, which main() uses directly.
In the second example, functionOutsideMain() has its own A parameter which it uses, whereas main() still uses the global A variable instead.
functionOutsideMain() takes its A parameter by value. When main() passes in the global A variable to functionOutsideMain(), a copy of that A is made, and so any value that functionOutsideMain() assigns to its A parameter will not be applied to the global A variable, which is why main() does not see the change.
To do what you are attempting, you need to have functionOutsideMain() take its A parameter by reference instead:
void functionOutsideMain(int** &A, int n, int m)
Now, any value functionOutsideMain() assigns to its A parameter will be assigned to the global A variable, and thus will be seen by main().
Hey I didn't get what you meant by not working, but the possible solutions to the problems could be
No need to pass A again to functionOutsideMain since A is already global
When you pass A to functionOutsideMain, the actual parameter A becomes the formal parameter A, and now here's the problem, in C there is only pass by value(unlike pass by reference in C++). So when you pass A to the function, a new pointer gets created in the function and when you allocate a chunk of memory to it, the new pointer points to that memory and not the old pointer that you are using in main function.
One possible solution for this would be
void function_outside_main(int ***A, int n, int m) {
int **Aptr = (*A);
// And then use Aptr to allocate memory as you did
}
Else don't pass A as function parameter since it's a global variable
I am learning classes in c++ so I try different things to get used to the classes. Here I am trying to pass a pointer to a class function:
class Pointerss{
int size;
public:
Pointerss(int);
void f();
int *a;
};
Pointerss::Pointerss(int siz){
size = siz;
}
void Pointerss::f(){
cout<<"Size is:"<<size<<"\n";
for (int i=0; i<size; ++i) {
cout<<"a is:"<<a[i]<<"\n";
}
}
int main() {
int size = 5;
Pointerss dd (size);
Pointerss * p = new Pointerss(size);
p[0]=1; p[1]=2; p[2]=3; p[3]=4; p[4]=5;
p->a;
dd.f();
return 0;
}
So the "size" is initialized by a constructor and when "f()" is called the correct digit is printed. But when I assign "p" to "a" ("p->a") and then call "f()" some random numbers are printed. My computer prints :
Size is:5
a is:0
a is:0
a is:1
a is:0
a is:1606416856
Program ended with exit code: 0
what is the difference between "a" and "size" and what should I do to pass a pointer to a function?
Random numbers are printed because Pointerss::f dereferences dd.a which you never initialized. Dereferencing an uninitialized pointer results in undefined behaviour.
That's not the only bug you have. You also allocate memory for a single Pointerss object, which is pointed by p, but then proceed to construct objects in p[1..4] which point to unallocated memory. That also results in undefined behaviour.
Thirdly, you never deallocate the memory that you allocated with new.
Step 1 would be to understand pointers. When you make a int* you only reserve memory to store the pointer itself. You don't reserve memory for any int. So when you try to print the integers you just get random numbers (or perhaps a program crash).
So your class can't hold any integers. You need to change it so that you reserve memory in the constructor and release it in the destructor.
class Pointerss{
int size;
public:
Pointerss(int);
~Pointerss();
void f();
int *a;
};
Pointerss::Pointerss(int siz){
size = siz;
a = new int[size]; // Reserve memory for size integers
// Do some initialization if needed, e.g.
for (int i=0; i < size; i++) a[i] = i;
}
Pointerss::~Pointerss(){
delete[] a; // Release the memory again
}
void Pointerss::f(){
cout<<"Size is:"<<size<<"\n";
for (int i=0; i<size; ++i) {
cout<<"a is:"<<a[i]<<"\n";
}
}
Further you can't make a single pointer to an instance of the class, i.e.
Pointerss * p = new Pointerss(size);
and then use it like
p[0]=1; p[1]=2; p[2]=3; p[3]=4; p[4]=5;
because that is operating on 5 different instances.
Finally the code:
p->a;
does nothing!
You could do
p->a[0] = 5;
but it is unclear what you are trying to do.
Notice that dd and p are refering to two different instances of your class so changing something inside *p doesn't change dd at all.
If you had done:
Pointerss *p = ⅆ
then *p and dd would be the same instance.
When I compile this code it says "error C4700: uninitialized local variable 'b' used". I'm not sure what I have to do now to fix this problem. I'm neither an IT student or technican but I very like to learn C++ and I'm learning it by myself. I've been on this for 1 day.
Many thanks
#include <stdio.h>
#include <iostream>
//A.
//1--
void InputArray(int *a, int &n)
{
printf("Insert n = ");
scanf("%d", &n);
a = new int[n];
for (int i=0; i<n; i++)
{
printf("Enter the key's a[%d] values: ", i);
scanf("%d",&a[i]);
}
}
void main()
{
int *b, m;
InputArray(b, m);
}
b is passed by value, which means a copy will be made, but since it's not initialized, you get the warning. Simply initialize it:
int *b = nullptr;
or
int *b = NULL;
If you want the function to modify the caller's variable, then pass by reference:
void InputArray(int *&a, int &n)
^
Your version passes the uninitialised pointer by value; the function modifies a local copy of it, but leaves b in its uninitialised state.
The pointers are not default initialized, so your variable b is uninitialized, this is the source of error. You have to initialize this variable to fix this:
void main()
{
int *b = NULL, m;
InputArray(b, m);
}
After you fix this there is additional problem in your code. It seems from the way you call a function that you expect to persistently change pointer b passed into it, so that b will point into memory allocated with new after function returned. But you pass a pointer by value what means changes made in function will not be reflected in original variable b which will still point to what it pointed before the call to a function. (the array will be allocated inside function and will stay in memory after function returned but you will leak this memory as b won't point into it). To fix this you have to pass pointer by reference:
void InputArray(int*& a, int& n)
Also: where is delete? Remember: mapping new to delete is bijection: every new corresponds to single delete placed somewhere in code.
First of all, did you learn how to use an pointer correctly ? because if you know how to use pointer u should know that when you declare a pointer you need to be initialized to NULL before you can use it, correct me if i'm wrong.
Example
int *b = nullptr;
int *b = NULL;
int *b = 0;
int *b(0);
It's all the same thing but in an different way
I am trying to make a new array in my project
the code is:
#include <iostream>
using namespace std;
void makeArray( int *& arrayPtr, int size );
int main( )
{
int * arrPtr;
int size =10;
makeArray( arrPtr, size );
for(int j=0;j<size;j++)
{
cout<<arrPtr[j]<<endl;
}
}
void makeArray( int *& arrayPtr, int size )
{
int arr[size-1];
for(int i=0;i<size;i++)
{
arr[i]=0;
}
*&arrayPtr=*&arr;
}
According to the requirements i need to use the above "makeArray" method inorder to make the array.
When i run the code the output is garbage values not zero.....
any help will be appreciated
thank you
The way you are creating the array is on the stack, which means that it will not exist after the makeArray function finishes.
You will need to allocate the array on the heap.
So:
int arr[size-1];
should be:
int *arr = new int[size-1];
Also, I think you mean to do this in makeArray():
arrayPtr = arr;
Instead of:
*&arrayPtr=*&arr;
Which compiles but is more complex and is functionally the same thing in this context.
But you may prefer just returning an int* instead of taking a reference to the pointer.
Then when you are done using the array in main(), and set it to NULL just in case you accidentally use it again, like this:
for(int j=0;j<size;j++)
{
cout<<arrPtr[j]<<endl;
}
delete [] arrPtr;
arrPtr = NULL;
Why are you declaring a parameter as 'int *& arrayPtr'? Do you just need a pointer to an array? You should use 'int *arrayPtr' instead.
To answer your question, the problem is that you are declaring an array in the function makeArray's stack. Upon the completion of a function, that function's stack is destroyed, so you're passing the address of junk data. To avoid this, use dynamic memory allocation instead.
EDIT: Also, you should use memset instead of a for loop to zero an array. It's much faster.
The "arr" which you allocate in "makeArray()" is local. and when the functione is over the array is release. When you back to main you get garbage.
What you want to do, is to use the "new" operator to allocate this new array to be used in all program, unless you will free this memory by "delete".
so you can set your makeArray() to:
int* makeArray(int size )
{
int *arr = new[size];
for(int i=0;i<size;i++)
{
arr[i]=0;
}
return arr;
}
the in you main you need to initialize your arry by:
int * arrPtr = makeArray(10);
just don't forget to release this memory after you finsh:
delete[] arrPtr ;