Can a pointer be decleared as void storing chars? - c++

char* pointer = new char [5];
strcpy_s(pointer,4, "foo");
I am not fully understanding how pointers work. In my understanding the variable pointer is supposed to store the starting address of the new allocated string of chars. If so why is it important that the pointer is a char since its only storing an address.
why can't i just type
void* pointer = new char [5]
Thanks.

the pointer needs to know the size of its element, thanks to it you can use [] operator to reach a certain element of the array, how else would it know how much memory it has to move to get to the n-th element? If you could declare a pointer to any type as void, then it would have to automatically deduce the type it points to. Consider this piece of code:
char* pointer = new char[5];
pointer[3] = 'a';
for void* this would not be possible. I suppose that the strcpy_s function expects the first parameter as char*, not void* and that is the reason why your code doesn't compile. Pointer itself just allows you to know where some variable/array or even function is in memory, but when you specify pointer's type it gives it more flexibility.

Related

Dynamic arrays and pointer notation

Is pointer a variable or an address?
Because int** array= new int*[4] is so confusing.
For int** array in this code, the pointer becomes variables to store the pointer addresses, and new int*[4] becomes addresses that will be stored in another pointer.
What am I understanding wrong?
Pointer is a data type, similar to int or char. The data here is a memory address. Pointers are qualified with the types of values expected to be located in the memory at the referred addresses. As other data types, pointers could be used as types for variables, function arguments, array elements etc.
So, int **array is a variable of type int ** which means a pointer to a value of type int * located somewhere in the memory. In turn, int * means a pointer to a value of type int located somewhere in the memory. Or, in short, int ** is a pointer to a pointer to an int.
Expression new int*[4] means allocate in the memory an object of type int *[4] and return a pointer to it. Type int *[4] means an array of four elements of type int * where int *, as we already know, means a point to int value.
So, in the initialization, the types of the left part (int **) and of the right part (int *[]) are different. However, C++ is able to automatically convert arrays into pointers in case the type of array element is the same as the type of the value referred by the pointer. In our case, array element type is int * and the same is the type referred by the pointer. When an array is converted to a pointer, the resulting pointer will refer to the first element of the array.
In this declaration
int** array= new int*[4];
array is a variable that is initialized by the address of the first element of a dynamically allocated array with the element type int *.
If you have an array declared like
T array[N];
where T is some type then a pointer to the first element of the array can be declared like
T *p = array;
If to take into account your array then just T is equal to int *.
Simply put, a pointer is a variable that can store the address of another variable instead of an int or a float or some other value like a "normal" variable.
Like any other variable, the pointer itself also has an address so you can have a pointer to pointer, i.e. a pointer that stores the address of another pointer.

Double Pointers and a Parenthesis between them

I am learning c pointer and I follow c4learn as tutorial. In pointer to array of string section, which has following code:
char *arr[4] = {"C","C++","Java","VBA"};
char *(*ptr)[4] = &arr;
I didn't get what is
*(*ptr)[4]
? Wasn't it possible to use it like
**ptr
instead?
Update1:
Currently I am in the next section, function pointer and I saw again similar code:
void *(*ptr)();
char *(*ptr)[4]
is a pointer to a length 4 array of pointers to char (char*). Since arr is a length 4 array of char*, ptr can be made to point to arr by assigning it the address of arr, &arr.
void *(*ptr)();
Is a pointer to a parameterless function returning void*. For example
void* fun(); // function
void *(*ptr)(); // function pointer
p = fun; // function pointer points to function
C syntax can be quite confusing, so it may be easier to illustrate this with some examples. Note that whitespaces between T and ; make no difference.
T name[N]; // size N array of T
T * name[N]; // size N array of pointer to T
T (*name)[N]; // pointer to size N array of T
T ** name[N]; // size N array of pointer to pointer to T
T *(*name)[N]; // pointer to size N array of pointer to T
char *ar[4];
Declares ar as an array of four pointers to chars.
To declare a pointer, you take the declaration of something it can point to, and replace the variable name with (*some_other_name).
So char *(*ptr)[4]; declares ptr as a pointer to an array of four pointers to chars. Normally you can drop the brackets, but in this case, char **ptr[4]; would declare ptr as an array of four pointers to pointers to chars which is not what we want.
Similarly for a function pointer. void *fn() declares a function. void *(*ptr)() declares a pointer that could point to fn. void **ptr() would declare a function with a different return type.
Wasn't it possible to use it like **ptr instead?
Yes, assuming you mean like ptr2 below:
const char* arr[4] = {"C","C++","Java","VBA"};
const char* (*ptr)[4] = &arr;
const char** ptr2 = arr;
There is a difference though... with ptr the type still encodes the array length, so you can pass ptr but not ptr2 to functions like the one below:
template <size_t N>
void f(const char* (&arr)[N]) { ...can use N in implementation... }
Currently I am in the next section, function pointer and I saw again similar code: void *(*ptr)();
That creates a pointer to a function - taking no arguments - returning a void* (i.e. the address of an unspecified type of data, or nullptr).
char *(*ptr)[4] is an array pointer to an array of pointers.
With less obfuscated syntax: if you have a plain array int arr[4]; then you can have an array pointer to such an array by declaring int (*arr_ptr)[4].
So there are arrays, regular pointers and array pointers. Things get confusing because when you use the array name by itself, arr, it decays into a regular pointer to the first element. Similarly, if you have a regular pointer and let it point at the array, ptr = arr; it actually just points at the first element of the array.
Array pointers on the other hand, points at the "whole array". If you take sizeof(*arr_ptr) from the example above, you would get 4*sizeof(int), 4*4=16 bytes on a 32-bit machine.
It should be noted that an array pointer a mildly useful thing to have. If you are a beginner, you don't really need to waste your time trying to understand what this is. Array pointers are mainly there for language consistency reasons. The only real practical use for array pointers is pointer arithmetic on arrays-of-arrays, and dynamic allocation of multi-dimensional arrays.

what the differences between char** and char*[]

Recently, I need to declare a string array, so I wrote down the following statement:
const char** directories = {"cricket_batting", "cricket_bowling", "croquet", "tennis_forehand", "tennis_serve", "volleyball_smash"};
However, g++ showed me the error:
error: scalar object ‘directories’ requires one element in initializer
So I changed the statement to this:
const char* directories[] = {"cricket_batting", "cricket_bowling", "croquet", "tennis_forehand", "tennis_serve", "volleyball_smash"};
This time, it was right. But I can't exactly know the difference between char** and char[].
= {...};
Initialisation of this form is known as list-initialization.
const char**
This type is a "pointer to pointer to const char".
const char*[]
This type is an "array of pointer to const char".
Simply put, you cannot initialise a pointer with list-initialization. You can initialise an array with list-initialization; it initializes each of the elements in the array with the items in the braced list.
The reason comes down to what exactly you get from a declaration. When you declare a const char**, all you get is a single pointer object. It's a const char**, which is a pointer promising to point at a pointer to const char. Nonetheless, all you actually have is the outer pointer. You can't then initialise this as though it's an array, since you only have one pointer. Where exactly are you going to store the elements of the initialization list? There is no array of pointers in which you can store them.
However, when you declare a const char*[], what you get is an array of pointers. The size of the array is determined by the size of the list because you have omitted it.
The former is a pointer to a pointer to const char while the latter is an array to pointer to const char. The latter is the correct way to initialize an array of strings.
You would need to allocate memory using new to set up char** , for you can't simply initialize pointers with { }.
When you write int a[] we are making an array of integers. Similarly when you write const char* directories[] you are creating an array of char* pointers. Now each char* can point to a char or a string as in your case. This creates individual string constants and assigns the base address of each to the corresponding pointer in the array
char **directories is pointer to a pointer and you can't assign value to a pointer using { .. }

Cannot convert from 'T[N][2]' to 'T[][2]'

I have an API taking some options:
void init_api(const char* options[][2]);
I am allowed to pass a NULL pointer for no options, alternatively, an options array such as this can be passed:
const char* some_options[][2] = { {"opt1", "val1"},
{"opt2", "val2"},
{0,0}
};
This works without problems:
...
init_api(some_options);
... or ...
init_api(NULL);
...
However, this fails to compile:
const char* my_options[][2] = NULL; // error C2440: 'initializing' : cannot convert from 'int' to 'const char *[][2]'
if(...) {
my_options = some_options; // error C2440: '=' : cannot convert from 'const char *[4][2]' to 'const char *[][2]'
}
init_api(my_options); // no error here
What is going on here? Can someone explain this?
To declare an empty array of array of pointers to const char, you should use:
const char* my_options[][2] = {};
You need to declare a pointer to an array of pointers to const char instead. I recommend using a typedef to simplify the syntax.
typedef const char* array_of_two_cstring[2];
array_of_two_cstring* my_options = NULL;
if (...) {
my_options = some_options;
}
init_api(my_options);
In C++ (it is herited from C), array can be implicitly converted to pointer (only once though, that is char[] is compatible with char* but char[][] is compatible with char*[] but not `char**). However, the variable cannot be reassigned. So here you need to use a pointer instead of an array.
The init_api option accepts NULL as a parameter because for the compiler, its prototype is void init_api(char const* (*)[2]) (the first array degenerated into a pointer), and NULL is a valid pointer.
The compiler must know the array size.
If you omit the size of the array (ie: using []) you need to initialize the array with the definition, in order to let the compiler count how many items that array will contain.
Moreover you are assigning a pointer (NULL) to an array: const char *x[][2] is an array of two pointers to const char.
Edit:
In C++ (as in C), arrays can decay into pointers when you use them (with three exceptions which are not interesting here).
When you pass an array to a function expecting an array, what happens is that you actually pass a pointer to the array, since the array decays; you cannot pass an array by value in C or C++.
For this reason you can pass NULL to your function; the function parameter will be NULL, and if you try to access the array within your function (options[0]) your application will crash: you'll be dereferencing an invalid pointer.
You cannot however set your array variable to NULL, since it's not a pointer, it's an array: it will only decay when you'll use it in an expression.
const char* options[][2]
is an array of const char* pointers. You can't assign a pointer to an array.
A parameter declared as being an array of type T[N] or T[] becomes actually a parameter of type T*. Same is done for functions (a parameter declared as R(Params) becomes actually a parameter of type R(*)(Params...)).
Such transformation however is not done for other declarations. The reason it's done for function by-value parameters is that there is no way in C to actually copy an array directly (that is, to actually copy its contents) and it doesn't make sense to try and copy a function either, so such parameters are transformed in a way that conveys their purpose in a meaningful way.
So while you are initializing a pointer in the function parameter case, you are trying to initialize an array in the other case.

ELI5: What is the data type of `int *p[]`

I don't understand what the datatype of this is. If its a pointer or an array. Please explain in simple terms. To quote what was in the book-
If you want to pass an array of pointers into a function, you can use the same method that you use to pass other arrays—simply call the function with the array name without any indexes. For example, a function that can receive array x looks like this:
void display_array(int *q[])
{
int t;
for(t=0; t<10; t++)
printf("%d ", *q[t]);
}
Remember, q is not a pointer to integers, but rather a pointer to an array of pointers to
integers. Therefore you need to declare the parameter q as an array of integer pointers,
as just shown. You cannot declare q simply as an integer pointer because that is not
what it is.
cite: C++: The Complete Reference, 4th Edition by Herbert Schildt, Page 122-123
This is how it's built up:
int is the type "int".
int* is the type "pointer to int"
int* [] is the type "array (of unknown bound/length) of pointer to int"
int* p[] is the declaration of a variable or parameter named p of the type above.
... pointer to an array of pointers to integers
No it's not. q is the type int *[]. Which is an invalid (or possibly incomplete, depending on context) type in C++, and only valid in some places in C. Arrays must have a size.
The type int *[] is an (unsized) array of pointers to int. It is itself not a pointer.
The confusion probably comes from the fact that an array can decay to a pointer to its first element.
For example, lets say we have this array:
int a[20];
When plain a is used, it decays to a pointer to its first element: a is equal to &a[0].
int *p[]
// ^
p is
int *p[]
// ^^
p is an array of unspecified size (possibly illegal, depends on context)
int *p[]
// ^^^^^
p is an array of unspecified size of pointers to int
Meaning each element of p is a pointer:
int foobar = 42;
p[0] = NULL;
p[1] = &foobar;
I don't understand what the datatype of this is
If it's any comfort, neither does the author of the book you are reading.
Remember, q is not a pointer to integers, but rather a pointer to an array of pointers to integers.
This is bullschildt.
Before adjustment of parameters, q is an array of pointers to integers.
After adjustment of parameters, q is a pointer to the first element of an array of pointers to integers. Equivalent to int** q, a pointer to pointer to an int.
Nowhere is it "a pointer to an array of pointers to integers". That would have been int* (*q)[].
I would advise to stop reading that book.
The key here is that any array that is part of a parameter list of a function, gets adjusted ("decays") into a pointer to the first element. So it doesn't matter if you type int* q[666] or int* q[], either will be silently replaced by the compiler with int** "behind the lines".
This is actually the reason why we can write [] in a parameter list - normally an empty array would be an incomplete type that can't be used before completion elsewhere. But since parameters always get adjusted, they are never of array type, and it doesn't matter that the original type was incomplete.