I have program
void alloc(char **p)
{
*p=(char*)malloc(sizeof(char)*3);
(*p)[0]='a';
(*p)[1]='f';
(*p)[2]='\0';
}
main()
{
char p[]="hrrgr";
alloc(&p);
printf("%s",p);
}
It prints nothing. Please explain this.
I know by passing char*p ; and alloc(&p) will do the trick. But the purpose of my question is to understand the output I am getting.
p is an array of 6 characters. Therefore p is of type char[6]. &p is then of type pointer to char[6] type, i.e., char (*)[6]. When you pass an array to a function, it evaluates to a pointer to its first element. Thus when you are passing a char (*)[6] type value to your alloc function, you are assigning a char (*)[6] type to a char ** type. They are incompatible types and have different pointer arithmetic. You can't make char (*)[6] behave like a char ** type, even by typecasting which will only suppress compiler warning.
This is not allowed: p is an array of 6 characters, not a char pointer. You should not treat &p as a char** pointer.
If you want to fix this code, declare p like char*, not as an array:
char *p="hrrgr";
alloc(&p);
Running demo on ideone.
&p is of type char (*)[6] but your function alloc expects an argument of type char **. You are passing wrong type parameter.
try this...
void alloc(char **p)
{
*p=(char*)malloc(sizeof(char)*3);
(*p)[0]='a';
(*p)[1]='f';
(*p)[2]='\0';
}
main()
{
char *p;
alloc(&p);
printf("%s",p);
}
When ever you declare an array then there will be continuous allocation of memory but here your are changing starting 3 elements memory which changes the whole location of array and printing garbage...
Related
I am starting to learn pointers in C.
Why do I have an error in line 8 at &i?
This is the source:
char * func(char *d, char *str)
{
return d;
}
int main(int argc, char *argv[])
{
char *i = NULL;
func(&i, "aaa"); // line 8. here I have the error (in "&i")
}
You are passing char** and the function expects a char*. You need to pass i without the address of & operator, because this way you are taking the address of the pointer.
Just pass func(i, "aaa");
The type of &i is not char * it is char * *.
You should go through this
How do pointer to pointers work in C?
When you write &i, you are passing the memory address of i, but since i is already a char*, the type of &i is char** (pointer to pointer to char). You therefore have an extraneous & that is causing a type mismatch. Simply remove the & and pass i to the function with taking its address:
func(i, aaa); //no need to use & on a variable that is already a pointer
As per your function prototype func(char *d, char *str) first parameter accepts pointer of char type and in char *i; i is a pointer of char type so pass it directly to function.
If you want to pass &i to the function you need to have pointer to pointer variable that is char **d.
#include <stdio.h>
// this works
void print_stuff (void* buf) {
printf ("passed arg as buf*: %s\n", buf);
}
/* This works */
void print_stuff_3 (char* buf) {
printf ("passed arg as char*: %s\n", buf);
}
// this does not work
void print_stuff_2 (char** buf) {
printf ("%s\n", *buf);
}
int main () {
char s [] = "hi";
printf ("s = %s\n", s);
// these work
print_stuff (&s);
print_stuff_3 (&s);
// this results in a Segfault
print_stuff_2(&s);
return 0;
}
I am a bit confused about the way things are passed around in C. I feel like &s should be of type char**, but it behaves as if it is of type char* when passed to a function. Why does this behaviour happen?
In particular, print_stuff_2 segfaults, whereas I thought that print_stuff_3 would give an error.
EDIT: To clarify, I expected print_stuff(&s) and print_stuff_3(&s) to fail (while they succeed), while print_stuff_2(&s) fails, whereas I feel it should succeed.
You need to remember that strings are not fundamental types in C. They are arrays of characters. Therefore
char s [] = "hi";
makes s a char * (in terms of variable type), i.e. a pointer to the first character of a 3 character array (h, i and NUL).
So in order to pass a pointer to the string, you what to use your print_stuff_3, as printf()'s %s argument takes exactly that (a pointer to the string, i.e. a pointer to the first character). Call this with print_stuff_3(s).
print_stuff works because a pointer is a pointer. It will be translated to a void * pointer on calling print_stuff, then printf()'s %s will convert it back to a char *. Call this with print_stuff(s).
print_stuff_2 doesn't work because you are taking the address of where s is stored. Had you written char *s = "hi"; that would work if you used print_stuff_2(&s). You'd pass the address of the pointer, then dereference that (to get the value of the pointer, i.e. the pointer to the first character) in by using *buf. Except buf then would be a poor choice of name, as you would be passing a pointer to a pointer to characters.
The complication is as follows. As it is, you are doing &s which just returns s when you have
char s [] = "hi";
(see How come an array's address is equal to its value in C? ), but returns the address at which the pointer variable s is stored on the stack if you have:
char *s = "hi";
Taking the address of an array doesn't really make sense (so evaluates to the address of the first element). You need to use char *s = "hi"; if you want to take the address of the pointer.
In C, array names are decays to pointer to its first element when passed to a function in most cases. When passing s to the function print_stuff, s decays to pointer to h. No need to pass it with &. &s is of pointer to array (char (*)[3]) type, i.e, it is giving the address of the entire array s.
In function call
print_stuff_3 (&s);
your compiler should warn you
[Warning] passing argument 1 of 'print_stuff_3' from incompatible pointer type [enabled by default]
I feel like &s should be of type char**, but it behaves as if it is of type char* when passed to a function. Why does this behavior happen?
No. You thought wrong. &s is of type char (*)[3].
void print_stuff (void* buf) & void print_stuff_3 (char* buf) In both functions, buf is of char * taking address as argument. Which should be print_stuff (s) & print_stuff_3 (s) respectively as s is the base address of char array s. So you shouldn't pass &s which is address of s.
As the below function buf is of type char **, it will expect address of address like print_stuff_2(&s) provided your declaration is char *s = "hi",
void print_stuff_2 (char** buf) {
printf ("%s\n", *buf);
}
My XCode (default compiler should be clang?) shows me on this code a warning:
Incompatible pointer types passing 'char *(*)[2]' to parameter of type 'char ***' (when calling func)
void func (char ***arrayref, register size_t size) {
/// ...
}
int main()
{
char *array[2] = {"string", "value"};
func(&array, 2);
}
while this code is no problem (=no warning):
void func (char **arrayref, register size_t size) {
/// ...
}
int main()
{
char *array[2] = {"string", "value"};
func(array, 2);
}
While this removes the warning
func((char***)&array, 2);
I still don't know why the first emits a warning, while the latter doesn't.
Also, when the first is a problem, I'd also expect that the first emits a warning like:
Incompatible pointer types passing 'char *[2]' to parameter of type 'char **'
Time for a brief refresher on array semantics.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element in the array.
The expression array in your code has type "2-element array of char *", or char *[2]. When you pass it as an argument to func, as in
func( array, 2 );
the expression is converted to an expression of type "pointer to char *", or char **, which is the type your function is expecting, and the value of the expression is the address of the first element: array == &array[0]. This is why you don't get the warning for the second code snippet.
In the first snippet, the array is an operand of the unary & operator, so the conversion to a pointer type doesn't happen; instead, the type of the expression is "pointer to 2-element array of char *", or char *(*)[2], which is not compatible with char **. The address value is the same (the address of the first element of the array is the same as the address of the array itself), but the types don't match, hence the warning.
So why does this matter? A pointer is just an address, and all address are the same, right? Well, no. A pointer is an abstraction of an address, with associated type semantics. Pointers to different types don't have to have the same size or representation, and pointer arithmetic depends on the type of the pointed-to type.
For example, if I declare a pointer as char **p;, then the expression p++ will advance the pointer to point to the next object of type char *, or sizeof (char *) bytes from the current address. If p is declared as char *(*p)[2], however, the expression p++ will advance p to point to the next two-element array of char *, which is 2 * sizeof (char *) bytes from the current address.
char *array[2] = {"string", "value"};
is an array with 2 elements of char *.
Using array as an address results to a pointer to the first element, i. e. of type char **.
Using &array results to a pointer to the same place, but of type char *(*)[2] (not sure if the spelling is right).
This is not the same as a char *** - the representation in memory is completely different.
To be more verbose,
+++++++++++++++++++++++
+ array[0] + array[1] +
+++++++++++++++++++++++
this is the array.
char ** p1 = array; // is a pointer to the first element, which in turn is a pointer.
char *(*p2)[2] = &array; // is a pointer to the whole array. Same address, but different type, i. e. sizeof(*p1) != sizeof(*p2) and other differences.
char ***p3 = &p1; // Now, p1 is a different pointer variable which has an address itself which has type `char ***`.
Here's an example of how to do what you want and change what array points to:
char *array2[] = {"string", "NewValue"};
void func0 (char **arrayref, register size_t size) {
puts(arrayref[1]);
}
void func1 (char ***arrayref, register size_t size) {
puts(arrayref[0][1]);
*arrayref= (char **) array2;
}
int main()
{
char *array[] = {"string", "value"};
char **foo = array;
func0(foo, 2);
func1(&foo,2);
func0(foo, 2);
}
You have an array of type char *[2] i.e. array of 2 pointers to char. It is an array of fixed size with automatic storage duration. The only thing that your function can do with this kind of array is to either use its elements or to change them (it can not resize it or deallocate it... therefore it makes no sense to try to make it possible to change the array itself ~> in other words: you don't really need a pointer to this kind of array).
Here's a simple example:
void func (char *arrayref[2]) {
printf("%s", arrayref[1]);
arrayref[1] = "new value";
}
int main() { {
char *array[2] = {"string", "value"};
func(array);
printf(" -> %s", array[1]);
return 0;
}
or alternatively changing func to take an array of unspecified size making it usable with char *[X] for any X, not just 2 (in that case it makes sense already to pass the array's size):
void func (char *arrayref[], size_t size) {
if (size > 1) {
printf("%s", arrayref[1]);
arrayref[1] = "new value";
}
}
with one way or other, this program would output value -> new value.
If you need your function to be able to resize this array or affect the array itself in some other way, you should consider using dynamically-allocated array and passing in form of char**.
Basically, I have an array of char* that I want to pass and modify in this function, so I pass in a pointer to an array of char*. That is, I want to pass a pointer to char* arr[]. What is the difference between the two?
As always, http://cdecl.org is your friend:
char * (*arr)[] - "declare arr as pointer to array of pointer to char"
char *** arr - "declare arr as pointer to pointer to pointer to char"
These are not the same. For a start, the first is an incomplete type (in order to use a pointer to an array, the compiler needs to know the array size).
Your aim isn't entirely clear. I'm guessing that really all you want to do is modify the underlying data in your array of char *. If so, then you can just pass a pointer to the first element:
void my_func(char **pointers) {
pointers[3] = NULL; // Modify an element in the array
}
char *array_of_pointers[10];
// The following two lines are equivalent
my_func(&array_of_pointers[0]);
my_func(array_of_pointers);
If you really want to pass a pointer to an array, then something like this would work:
void my_func(char *(*ptr)[10]) {
(*ptr)[3] = NULL; // Modify an element in the array
}
char *array_of_pointers[10];
// Note how this is different to either of the calls in the first example
my_func(&array_of_pointers);
For more info on the important difference between arrays and pointers, see the dedicated chapter of the C FAQ: http://c-faq.com/aryptr/index.html.
If you have a function that has char *(*arr)[] as a parameter, you will need to pass in an array with the address operator:
void afunc(char *(*arr)[]);
char *charptra, *charptrb, *charptrc;
char *arr[] = {charptra, charptrb, charptrc};
afunc(&arr);
On the other one, you have to pass a pointer that points to a pointer that points to a pointer:
void afunc(char ***);
char arr[] = "str";
char *arrptr = arr;
char **arrptrptr = &arrptr;
char ***arrptrptrptr = &arrptrptr;
afunc(arrptrptrptr);
I was just going through certain interview questions. Got this structure related issue, I m not understanding what is happening wit the output, Please if some could explain the reason.
When is use a character pointer in the structure like
#include <stdio.h>
struct name {
char *array;
}variable;
int main( int argc, char * argv[] ){
variable.array="hello";
printf( "%s\n", variable.array );
}
The output is hello printed, but when change the structure variable to
struct name {
char array[10];
}variable;
The compiler throws an error "incompatible types in assignment" at
variable.array="hello";
I am really confused as to where i am missing the point. Why does it show the error like assignment problem?? Please correct me
Thank you
You can only initialize array like that at the time of declaration only,
else you need to use
strcpy(variable.array,"hello");
you can't even do like that with a simple char array
char a[10];
a="hello";
the complier will tell :
incompatible types when assigning to type ‘char[10]’ from type ‘char *’
because "hello" is a string literal that is being held by a pointer which can't be assigned like this to an array.
In C the term "hello" means "a pointer to a string that has the chars 'hello\0' in it".
So when you assign array="hello" in the first case you are assigning the pointer to the string into a pointer variable. Which is right.
In the second case you try to assign a pointer to an array which is wrong!
you can't assign value to an array.
It raises an error because an array of char and a pointer to char are different things.
An array is not a pointer. A pointer is not an array. Sometimes a pointer might point to an array. But even when a pointer points to an array, it's not an array.
Your compiler gives an address to variable.array at compile time. It also gives an address to the string literal "hello". They're not the same address. The string literal and the array (or "the buffer") are in different places; logically, the string has to be copied into the buffer.
#include <stdio.h>
#include <string.h>
struct name {
char array[10];
}variable;
int main( void ){
strcpy(variable.array, "hello");
printf( "%s\n", variable.array );
return 0;
}
You might find the C FAQ useful.
The first thing is array is a constant pointer to the first element in the
array,we can not change its address location once we declared..like
int a[3]; is equivalent to int *const a;
so we cant change the array address location
int a[3]={1,2,3};
a++;//its an error
int b[3];
b=a;//its also an error
but int *c;
c=a;//Not an error because c is a pointer to integer not constant pointer to integer
similar to
char str[10]="hello";
if i change like this
str="world";//its also an error
Pointers and arrays are always not equal, in some cases only like dereferencing
char a[10]="hello";
for(i=0;a[i]!='\0';i++)
printf("%c",a[i]);
for(i=0;a[i]!='\0';i++)
printf("%c",*(a+i));