I am a bit confused when you pass NULL as a parameter
for example
int* array_create( int* array,size)
{
array = new int[size];
return array;
}
int main()
{
int* array = array_create(NULL,10);//can we pass NULL in this case?
delete[] array;
return 0;
}
I know the example is kinda stupid, but I am wondering if we can pass NULL as the parameter when the function assigns some heap memory to a pointer and returns it?
When you call your function like this...
int* array = array_create(NULL,10);//can we pass NULL in this case?
...you are getting behaviour like:
int* array_create(...)
{
int* array = NULL;
size_t size = 10; // using size_t as you'd missed any type
array = new int[size];
return array;
}
Ultimately, array is initialised to NULL then shortly afterwards overwritten with the value returned by new, so the initialisation serves no purpose.
For this code, there was simply no point passing an array argument... you could have created a local variable directly:
int* array_create(size_t n)
{
int* array = new int[size];
return array;
}
...or even...
int* array_create(size_t n)
{
return new int[size];
}
I am wondering if we can pass NULL as the parameter when the function assigns some heap memory to a pointer and returns it?
This requirement doesn't make much sense, as the two things are unrelated. You can pass whatever you like, and return whatever you like.
More commonly, a function might do something like:
void dump_bytes(std::ostream& os, unsigned char* p, size_t n)
{
if (p)
for (size_t i = 0; i < n; ++i)
os << static_cast<int>(p[i]) << ' ';
}
In dump_bytes, specifying a p value of NULL would fail the if (p) condition, ensuring the function didn't invoke undefined behaviour by dereferencing via a NULL pointer, even if n was not 0.
Just summarizing from the comments:
Yes, it is completely valid, but in Your example it is completely useless (you know that)
Some examples of this in real code:
In OpenGL you can tell the API if the data you want is coming from is from a buffer:
glBufferData(..., nullptr);
But wait! That's not null, that's nullptr?
Well in a c++11 compiler nullptr is a better option. Because NULL often usually resolves to 0, a version of the method that takes an int instead of a pointer the compiler will choose the int.
Here's some more data on that:
http://en.cppreference.com/w/cpp/language/nullptr
Also, if you want to edit an array, you should pass a pointer to a pointer.
Related
Error in function realloc(): invalid pointer
int indZero = 0;
int *perZero=NULL;
int zero = 0;//Initialization
ProcessBit(zero,&indZero,&perZero);// Call function
void ProcessBit(int num,int *ind,int **mas)
{
mas=(int**)realloc(&mas,((*ind))*sizeof(int));// Error
mas[num-1]++;//it's correct line
}
A few problems:
The first argument to realloc is the original pointer (or NULL).
Your ProcessBit doesn't really emulate pass-by-reference correctly.
You can use a negative index.
mas is a pointer to a pointer to int, but you use it as a pointer to int.
A "fixed" version might look something like this:
void ProcessBit(int num, int *ind, int **mas)
{
int *temp = realloc(*mas, (*ind + 1) * sizeof(int));
if (temp == NULL)
{
// TODO: Handle error
// TODO: return or exit(EXIT_FAILURE)
}
*mas = temp;
(*mas)[*ind] = 0; // Initial initialization
if (num > 0)
{
(*mas)[num - 1]++;
}
++*ind; // Increase the size
}
Now, if this really was C++ (as you tagged your question) then you should be using std::vector instead, which would solve almost all your problems with much simpler code.
The parameters are wrong. Since you are trying to realloc a NULL pointer it should behave like malloc; however, the header declared in cstdlib is
void* realloc( void* ptr, std::size_t new_size );
The formal parameter mas is already the address of the pointer, so the call should be
*mas=(int*)realloc(*mas,((*ind))*sizeof(int));
(*mas)[num-1]++;
Since realloc handles and returns pointers by copy, not by reference.
You are passing the address of the memory location where the address of a memory location (NULL) is stored to your ProcessBit function, and then the address of that location to the realloc function. The function tries to reallocate memory where the variable mac is stored, on the stack. No wonder it's an invalid pointer.
By passing &mac you are simply taking a step in the wrong direction while dereferencing pointers.
I'm currently learning pointer. And when I create a pointer to an array with int type, I found that I can directly index the pointer without deferencing the pointer and the compiler still output exact items in my array. I do not understand why this works and why we don't need to first deference the pointer.
Code that without dereference
int arraySize = 5;
int* theArray = new int[arraySize];
for(int i = 0; i < 5; i++)
{
theArray[i] = i;
}
for (int i = 0; I < 5; i++)
{
std::cout << theArray[i] << std::endl;
}
And this gives me the output
Output without derefercing
However, when I wrote like this:
for (int i = 0; i < 5; i++)
{
(*theArray)[i] = i;
}
My compiler says that: Error: expression must have pointer-to-object type. (I'm using Visual Studio 2013.)
Any help would be appreciated.
Code that without dereference
[ code ]
That's incorrect. You are most certainly dereferencing your pointer:
theArray[i] = i;
That's a pointer dereference. The [] operator dereferences the pointer. This is equivalent to:
*(theArray+i) = i;
As you know, adding or subtracting a value to a pointer advances or decrements the pointer, producing a new pointer value, and then the pointer gets dereferenced.
Also:
*p = q;
is equivalent to
p[0] = q;
The [] operator is just a shorthand for adding an offset to a pointer, and dereferencing the resulting pointer with the * operator. The end result is exactly the same.
I do not understand why this works and why we don't need to first deference the pointer.
The first version is correct:
for(int i = 0; i < 5; i++)
{
theArray[i] = i;
}
because theArray[i] is actually *(theArray + i) - essentially pointer arithmetic is equivalent to array index.
On the other hand, the 2nd version is incorrect:
for (int i = 0; i < 5; i++)
{
(*theArray)[i] = i;
}
That's because (*theArray)[i] is actually pointer to array (not the array itself), and so it caused a type mismatch as the compiler already suggested.
A few other answers correctly say that *(theArray + i) is equivalent to theArray[i]. But the point I think you missed when learning is that unlike most objects a pointer to an array is not a pointer to the array that is then dereferenced, and then array logic, it is only a pointer to the first element of the array. That's why this:
int *myIntPointer = new int[5];
is NEARLY the same as this:
int myIntArray[5]; // "True" array on the stack
But you can also point it at something else:
int myInt = 10;
delete [] myIntPointer;
myIntPointer = &myInt;
It's also why doing the follow CAN give a compiler warning, but can also work (depends on the compiler):
myIntPointer = myIntArray; // Sometimes works, sometimes doesn't, compiler dependent
That's because allocating an array with new int[size] returns a pointer to an int not a pointer to an "array" type.
It's a weird corner case of C/C++ that arrays and pointers interact this way. You also run into it if you try and pass one of the "true" arrays into a function.
theArray[i] literally corresponds to *(theArray + i) so it already dereferences the pointer.
Indeed when you try to call operator[] on *theArray it yields you an error because it expects a pointer, not a real object.
You're actually asking the wrong question for your misunderstanding — you should be asking why you can write
int* theArray = new int[arraySize];
In c++, array types are not like other types, and have a number of special cases and rules that make them behave differently from other types. In particular, new T[N] does not return a "pointer to an N-long array of T", it returns a "pointer to T". (specifically, to the first element of the newly created array)
For a more mindboggling example of this, observe:
typedef int T[5];
T* p = new T; // this does not compile
int* q = new T; // this does compile
I have a working code for a function which takes a character and a number and forms a string by duplicating that character that number of times. Here is a piece that works perfectly fine.
char * buildstr(char c, int n)
{
char * pc = new char[n+1];
for (int i = 0; i < n; ++i)
{
*(pc+i) = c;
}
*(pc+n) = '\0';
return pc;
}
But if I use another logic where I directly increment the pointer itself directly then I get an error when I free up the memory in the main function using delete [].
What could be my problem ?
Thanks,
char * buildstr(char c, int n)
{
char * pc = new char[n+1];
for (int i = 0; i < n; ++i)
{
*pc = c;
pc++;
}
*(pc) = '\0';
return pc;
}
The problem is that you're returning the incremented pointer. delete[] has to be invoked with a pointer value that was returned by a call to new[], otherwise you get undefined behaviour. The same applies to calls to free and pointers returned by malloc, calloc etc.
In the second example, you are incrementing the value of the pointer. When you try to delete it, it is pointing to the last position of the array.
This way, when you call delete[] on it, it crashes as it expects pc to point to the address that was originally allocated using new[].
I encourage you to use the first approach as you will be able to keep track of the base address through the lifetime of pc. Moreover, I think it would be easier for you to do this using array notation.
Consider using:
pc[i] = c;
instead of
*(pc+i) = c;
As it is more idiomatic and easy to read. If you are simply exercising your pointer arithmetic, stick to the first approach that you described.
In the first function let's say that your pointer start at 0x00100.
when you do the loop you get to the next adress so for exemple let's say 4 loop:
0x00100
0x00101
0x00102
0x00103
but at the end you return the pointer on the 0x00100 beceause you used index *(pc+i) where i is the index, so it is good.
Now on the second function you are doing the same exept that your are moving your pointer itself without index so you return your pointer at the last adress
0x00103
That is wy your second function doesn't work
A very general question: I was wondering why we use pointer to pointer?
A pointer to pointer will hold the address of a pointer which in turn will point to another pointer. But, this could be achieved even by using a single pointer.
Consider the following example:
{
int number = 10;
int *a = NULL;
a = &number;
int *b = a;
int *pointer1 = NULL;
pointer1 = b; //pointer1 points to the address of number which has value 10
int **pointer2 = NULL;
pointer2 = &b; //pointer2 points to the address of b which in turn points to the address of number which has value 10. Why **pointer2??
return 0;
}
I think you answered your own question, the code is correct, what you commented isn't.
int number = 10; is the value
int *pointer1 = b; points to the address where int number is kept
int **pointer2 = &b; points to the address where address of int number is kept
Do you see the pattern here??
address = * (single indirection)
address of address = ** (double indirection)
The following expressions are true:
*pointer2 == b
**pointer2 == 10
The following is not!
*pointer2 == 10
Pointer to pointer can be useful when you want to change to what a pointer points to outside of a function. For example
void func(int** ptr)
{
*ptr = new int;
**ptr = 1337;
}
int main()
{
int* p = NULL;
func(&p);
std::cout << *p << std::endl; // writes 1337 to console
delete p;
}
A stupid example to show what can be achieved :) With just a pointer this can not be done.
First of all, a pointer doesn't point to a value. It point to a memory location (that is it contains a memory address) which in turn contains a value. So when you write
pointer1 = b;
pointer1 points to the same memory location as b which is the variable number. Now after that is you execute
pointer2 = &b;
Then pointer2 point to the memory location of b which doesn't contains 10 but the address of the variable number
Your assumption is incorrect. pointer2 does not point to the value 10, but to the (address of the) pointer b. Dereferencing pointer2 with the * operator produces an int *, not an int.
You need pointers to pointers for the same reasons you need pointers in the first place: to implement pass-by-reference parameters in function calls, to effect sharing of data between data structures, and so on.
In c such construction made sense, with bigger data structures. The OOP in C, because of lack of possibility to implement methods withing structures, the methods had c++ this parameter passed explicitly. Also some structures were defined by a pointer to one specially selected element, which was held in the scope global to the methods.
So when you wanted to pass whole stucture, E.g. a tree, and needed to change the root, or 1st element of a list, you passes a pointer-to-a-pointer to this special root/head element, so you could change it.
Note: This is c-style implementation using c++ syntax for convienience.
void add_element_to_list(List** list, Data element){
Data new_el = new Data(element); // this would be malloc and struct copy
*list = new_el; //move the address of list, so it begins at new element
}
In c++ there is reference mechanismm and you generally you can implement nearly anything with it. It basically makes usage of pointers at all obsolete it c++, at least in many, many cases. You also design objects and work on them, and everything is hidden under the hood those two.
There was also a nice question lately "Why do we use pointers in c++?" or something like that.
A simple example is an implementation of a matrix (it's an example, it's not the best way to implement matrices in C++).
int nrows = 10;
int ncols = 15;
double** M = new double*[nrows];
for(unsigned long int i = 0; i < nrows; ++i)
M[i] = new double[ncols];
M[3][7] = 3.1416;
You'll rarely see this construct in normal C++ code, since C++ has references. It's useful in C for "passing by reference:"
int allocate_something(void **p)
{
*p = malloc(whatever);
if (*p)
return 1;
else
return 0;
}
The equivalent C++ code would use void *&p for the parameter.
Still, you could imagine e.g. a resource monitor like this:
struct Resource;
struct Holder
{
Resource *res;
};
struct Monitor
{
Resource **res;
void monitor(const Holder &h) { res = &h.res; }
Resource& getResource() const { return **res; }
}
Yes, it's contrived, but the idea's there - it will keep a pointer to the pointer stored in a holder, and correctly return that resource even when the holder's res pointer changes.
Of course, it's a dangling dereference waiting to happen - normally, you'd avoid code like this.
I have an array of type T which I pass as a pointer parameter to a function.
The problem is that I can't write new data to this array properly, without getting memory violation at the second try.
In this code I read integers from a text file and pass them to the function (part of template class of type T), in order to append them to the array.
After I finish to append the integers, I want to use the same array back in the Main.
Does someone know what's wrong with the code?
Thanks, Max
template<class T> int CFile<T>::read(T **apBuf, int aNum)
{
int readCounter = 0;
*apBuf = (T*)malloc(sizeof(T)*aNum);
for (int i = 0; i<aNum; i++)
{
T var = read();
if (var == NULL)
{
if (isEof)
{
return readCounter;
}
else
{
perror ("Error Reading File - Insufficient var type");
return -1;
}
}
else
{
*apBuf[i] = var;
readCounter++;
}
}
return readCounter;
}
*apBuf[i] = var;
This is parsed as if it was written:
*(apBuf[i]) = var;
This is obviously not what you want; apBuf is a pointer to a pointer to an array; you are treating it as a pointer to an array and you are dereferencing the ith element of it. What you really mean is:
(*apBuf)[i] = var;
*apBuf gives you "the object pointed to by apBuf," which is the array; then you obtain the ith element of the array.
That said, this is rather unusual: why not accumulate the data into a std::vector<T> and return that from the function? Then you don't have to worry about the explicit dynamic memory management. (Also, is T always a pointer type? If not, then var == NULL makes no sense.)
Well, you used malloc to allocate the array, and then tried to assign to it. This is undefined behaviour, because you have to construct the objects.
Oh, and you should really, really consider using self-owning resource classes, because malloc and this style of programming in general is hideously unsafe. What if T's copy constructor throws an exception? Memory leak. Just for example.
One issue you have is your using malloc instead of new. If T is a class the constructor won't be called.