Assume this code in C:
int a = 5;
int *b = &a;
*b = 6;
Notice that b had to be dereferenced using * to have a value reassigned.
However, the same doesn't go with a char pointer (a String):
char *name = "test";
name = "test2";
name did not have to be dereferenced. Why is that?
In this code snippet
int a = 5;
int *b = &a;
*b = 6;
the last assignment stores the integer constant to the object pointed to by the pointer b. That is the value of the object a is changed not the value (address) stored in the pointer b.
In this code snippet
char *name = "test";
name = "test2";
the value of the pointer itself is changed not the object pointed to by the pointer. So at first the pointer name pointed to the first character of the string literal "test" and then it is reassigned to point to the first character of the string literal "test2".
It is the similar to the following code
int a = 5;
int *b = &a;
int a2 = 6;
b = &a2;
If you want to change an object pointed to by a pointer of the type char * you could write
char s[] = "test";
char *name = s;
*name = 'T';
In this case the array s will have "Test".
Pay attention that you may not change a string literal. That is if instead of the array s you will write
char *s = "test";
char *name = s;
*name = 'T';
then the code will have undefined behavior.
Also bear in mind that in this declaration
char *s = "test";
the string literal having the type char[5] is implicitly converted to pointer to its first element.
The type of "test2" is already char[6] (which in turn decays to char*). There's simply no need to use address-of on the rvalue, or dereference the lvalue to do the assignment for the types to work out.
Why is that?
Because the two examples you show are not the same.
The were the same if you did:
/* your 1st example: */
int a = 5;
int *b = &a; /* b is a pointer to a what a is. */
*b = 6;
a equals 6 now.
/* your second example adjusted: */
char *a = "test";
char **b = &a; /* b is a pointer to a what a is. */
*b = "test2";
a points to "test2" now.
Related
I would like to reverse a String with an pointer to a function, which executes the String reverse.
I have the feeling that I did not grasp the concept of using pointer to variables or functions correctly, so I would be very thankful if someone could expain me, where I am thinking wrong here:
1) Define a pointer to a function:
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
2) Now in my main I define a pointer, which matches the function I defined above:
int main(void) {
char (*functPtr)(char);
functPtr = &strrev;
3) Now I define the String, which I want to reverse, define a new pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
4) Lastly I define a new String and write the result of the function, which call through the pointer, which points to the pointer to the function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
return(0);
}
Unfortunaly I get all kinds of error message such as:
Ü1.c:29:10: error: array initializer must be an initializer list or string literal
char t[50] = (*functPtr)(pointer[50]);
^
Ü1.c:27:5: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
pointer[50] = &str[50];
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
Ü1.c:29:30: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
char t[50] = (*functPtr)(pointer[50]);
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
2 warnings and 1 error generated.
1) Define a pointer to a function:
No, you did not define a pointer to function. You defined a function with the name strrev.
2) Now in my main I define a pointer, which matches the function I
defined above:
int main(void) {
char *(*functPtr)(char *);
functPtr = &strrev;
Yes, you defined a pointer to function and initialized it with the address of the function strrev. As function designators used in expressions are implicitly converted to pointers to function then you could write
int main(void) {
char *(*functPtr)(char *);
functPtr = strrev;
3) Now I define the String, which I want to reverse, define a new
pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
Except the definition of the character array that contains a string all other records do not make any sense. For starters the function strrev reverses a string in place. It does not create a reversed copy of the passed to it string.
If you want to declare a pointer that will get the address of the reversed string returned by the function that equal to the address of the original string then you could just write
char *pointer = functPtr( str );
4) Lastly I define a new String and write the result of the function,
which call through the pointer, which points to the pointer to the
function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
You already defined a pointer that will get the value returned from the function. So there is no sense to declare one more array. Moreover arrays do not have the assignment operator. And the function reversed the original string in place. Why are you going to create one more array with the duplicate copy of the original reversed string?! This entirely does not make a sense.
Your program can look the following way
#include <stdio.h>
#include <string.h>
char * strrev( char *s )
{
size_t n = strlen( s );
if ( n )
{
for ( char *first = s, *last = s + n; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char * ( *fp )( char * ) = strrev;
char s[] = "Hello, World";
puts( s );
puts( fp( s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
If you initially wanted that the function would not reverse the original string but make a reversed copy of the original string then in this case indeed there is a sense to define one additional character array that will get the reversed copy of the original string.
In this case the program can look like.
#include <stdio.h>
#include <string.h>
char *reverse_copy( char *s1, const char *s2 )
{
*( s1 += strlen( s2 ) ) = '\0';
while (*s2)
{
*--s1 = *s2++;
}
return s1;
}
int main(void)
{
char * ( *fp )( char *, const char * ) = reverse_copy;
char s[] = "Hello, World";
char t[sizeof( s )];
puts( s );
puts( fp( t, s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
Now the original character array s was not changed while the array t got the reversed copy of the original string stored in the array s.
I summarize my comments in this answer, as it gives more space for details of the comments.
char (*functPtr)(char); should be char *(*functPtr)(char *); as it takes a pointer to a char, not a char. Likewise it returns a pointer.
char *pointer[50]; would be an array of 50 pointers, You want to say "a pointer to an array of 50 chars". In C we don't say that. We just say "a pointer to a char" and don't say how many. So char *pointer; would be enough.
char t[50] = (*functPtr)(pointer[50]); is not correct in C.
You want to assign the result of funcPtr to the array t. But here you mix initialization with assignment.
char t[50]; declares an array of 50 chars. You can initialize it by giving it a value, for example char t[50] = "Hello World"; which will have the compiler copy "Hello World" to the array.
But you try to assign the function pointer to the array. You probably intend to put the result of the function into the array.
Note also that you cannot "assign" an array to another array. You can only copy it.
So the correct code would be:
char *(*functPtr)(char *);
functPtr = &strrev;
char str[50] = "Hello, World";
char t[50];
char *s= funcPtr(str); // call the function and save the returned pointer
strcpy(t, s); // now copy the result to your array.
printf("%s\n", t); // and print it
Note: char str[50] = "Hello, World"; is correct and, just so you'll know, char *str = "Hello, World"; is wrong. Why? Because the second str will point to read-only memory (a "string literal") and any attempt to modify it would abort the program. But here you did it right.
4I am trying to get a pointer address from a pointer to a pointer array, however I just get garbage when I run the code below. How do I retrieve the pointer address of one of the char * from the char ** array? Thanks for checking this out.
Specifically, I want to obtain the address of "wh" via "what" and assign it to "hi".
char * hi;
char * wh;
char ** what;
int main(void) {
char z[4] = "wx\0";
char a[4] = "ab\0";
hi = &z;
wh = &a;
what = (char **) malloc( 25 * sizeof(char));
what[0] = &hi;
what[1] = &wh;
printf("%s | %s\n", hi, wh);
hi = &what[1];
printf("%s | %s\n", hi, wh);
return EXIT_SUCCESS;
}
Corrected code:
#include <stdio.h>
#include<stdlib.h>
char * hi;
char * wh;
char ** what;
int main(void) {
char z[3] = "wx\0";
char a[3] = "ab\0";
hi = z;
wh = a;
what = malloc(2 * sizeof *what);
what[0] = hi;
what[1] = wh;
printf("%s | %s\n", hi, wh);
hi = what[1];
printf("%s | %s\n", hi, wh);
return 0;
}
The type of hi and wh is not the same as of &z and &a, even though they should yield the same value. Also you want what[1] in hi not the value of the memory location where it is. Also, in C you do not need to cast the return of malloc. However, in C++ the cast is required although its better to use the new operator.
Pointer Assignment
hi and wh are defined as pointer to char. So, change your assignment statements
from,
hi = &z; /* Type of &z is pointer-to-array-of-4-char */
wh = &a; /* Type of &a is pointer-to-array-of-4-char */
to,
hi = z; /* Type of z is pointer-to-char. Array name, here, decays into pointer
to first element of the array */
wh = a; /* Type of a is pointer-to-char */
what is defined as type, pointer to pointer to char. So, change your malloc statement
from,
what = (char **) malloc( 25 * sizeof(char)); /* what needs to hold char*'s,
you have allocated only for char's */
to,
what = malloc(25 * sizeof *what); /* what is of type char**. *what gives you char* */
Also, change your what , hi assignment statements
from,
what[0] = &hi; /* Type of what[0] is pointer-to-char;
Type of &hi is pointer-to-pointer-to-char */
what[1] = &wh; /* Type of what[1] is pointer-to-char;
Type of &wh is pointer-to-pointer-to-char */
...
hi = &what[1]; /* Type of hi is pointer-to-char;
Type of &what[1] is pointer-to-pointer-to-char */
to ,
what[0] = hi; /* Types are same */
what[1] = wh; /* Types are same */
...
hi = what[1]; /* Types are same */
Note:
The size of what is too high than what really required for the posted program. If you feel, you are going to have the same program, modify 25 to 2 in the malloc.
char * hi;
char * wh;
char ** what;
int main(void) {
char z[4] = "wx\0";
char a[4] = "ab\0";
hi = &z;
wh = &a;
First mistake; the types of the expressions &z and &a are both char (*)[4] (pointer to 4-element array of char), not char *. To fix this, drop the & from both:
hi = z;
wh = a;
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an array, 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 is the address of the first element in the array.
what = (char **) malloc( 25 * sizeof(char));
Don't cast the result of malloc; it isn't necessary1, and depending on the compiler version it can suppress a useful diagnostic. You also have a type mismatch. You want to space for 25 pointers to char, but you're only allocating enough for 25 plain chars. Rewrite that as
what = malloc( sizeof *what * 25 );
The type of the expression what is char **; thus, the type of the expression *what is char *. So sizeof *what will give you the same result as sizeof (char *). The above line allocates enough memory to store 25 pointers to char, and assigns the resulting pointer to what.
what[0] = &hi;
what[1] = &wh;
Again, drop the &; hi and wh are already pointers to char:
what[0] = hi;
what[1] = wh;
printf("%s | %s\n", hi, wh);
hi = &what[1];
Type mismatch; &what[1] has type char **, hi has type char *. Again, drop the &.
hi = what[1];
hi and wh now point to the same thing (what[1] == wh and hi == what[1], so hi == wh; that is, both hi and wh contain the same pointer value).
printf("%s | %s\n", hi, wh);
return EXIT_SUCCESS;
}
1. In C, that is; C++ is a different story, but if you're writing C++, you shouldn't be using malloc anyway.
I'm writing a function that reverses a cstring not in place but returns the reversed cstring. What exactly should the return type be?
#include <stdio.h>
#include <string.h>
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
int i;
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
int main()
{
char aStr[] = "hello";
char aStr2[] = "goodbye";
printf("%s %s", aStr, aStr2);
char* tmp = reverStr(aStr);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr);
return 0;
}
Gives
warning: function returns address of local variable [enabled by default]|
warning: initialization discards 'const' qualifier from pointer target type [enabled by default]|
I tried changing char* tmp to char tmp[] but it wouldn't compile. It confuses me when I should use an array and when I should use a pointer.
revStr is an array and ceases to exist after reverStr function exits. For more please read:
Where is the memory allocated when I create this array? (C)
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
return revStr; /* Problem - revStr is a local variable trying to access this address from another function will be erroneous*/
}
const char* reverStr(const char *str)
{
const char * revStr = str;
return revStr; //ok
}
A modifiable l-value cannot have an array type. An l-value is an expression which can come on the left side of an assignment. You use an array when you want to declare lots of variables of the same type and you can index it easily since its layout will be in a sense contiguous.
You use pointers when you want to keep changing the values of the address where you variable points to.
You can do this:
char * p = "test";
p = "new";
But you cannot do this:
char p[] = "test";
char *p1 ="test1";
p = p1; //error
Because their (arrays and pointers) types are not the same and the array p is a non-modifiable l-value.
Here is your fixed code. I tried to make less modifications.
char revStr[strlen(str)]; allocates a local variable(an array) and when you are out of the scope of the reverStr function, its memory is released, which will lead any further usage of its pointer to be UB(segfault in most cases).
A correct way is to allocate the string on the heap and return its pointer like this
char* x = (char*)malloc(strlen(str));
...
return x;
This requires user to be responsible to free the memory. Or you could pass another parameter to your function for the result string.
I think you should use malloc to allocate a new string.
const char* reverStr(const char *str)
{
char *revStr;//using pointer
int i;
revStr = (char*)malloc(strlen(str));//dynamic allocation
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
An array is a pointer point to the head of continuous memory.
for example:
int a[] = {1,2,3};
The address in memory maybe:
--1000
|1|
--1004
|2|
--1008
|3|
--1012
1000, 1004, and 1012 are the value of address in memory.
Thus, the value of array a should be 1000.
printf("%d",a);// Yes, you can do it and you may get the value of 1000.
Also, you can use the following code.
int a[] = {1,2,3};
int *b;
b= a;
printf("%d",b[1]);// you will get "2".
You can consider that pointer is a set and array is in the set.
Therefore, you can NOT do this;
int a[] = {1,2,3};
int c = 0;
int *b = &c;
a = b;//error
Suppose:
6 char arr[] = "ABC";
7
8 char *ptr = &arr;
9 char *ptr2 = &ptr;
Using ptr2, how can i access elements of c?
I would have thought the following would work, but ... it does not.
**ptr2[1]
You currently don't have a pointer-to-a-pointer.
Your code should be:
char c[] = "ABC";
char *ptr = c; // Note no &
char **ptr2 = &ptr; // Note **, not *. This is now a pointer-to-pointer
Then to access, you want this:
(*ptr2)[1]
ptr is a pointer to an array so its type is char (*ptr)[] not char *
And ptr2 is a pointer to a pointer of pointer so its type is : char (**ptr2)[].
I asked some time ago on an account I can't remember how to manipulate basic pointers and someone gave me a really good demo
for example
char *ptr = "hello" (hello = a char array)
so now *ptr is pointing at 'h'
ptr++ means moving the ptr to point at the next element, to get its value I do *ptr and that gives me e
ok so far everything works as I hope :D, but now I need to manipulate a char **ptr and was wondering how I do this in a way that mimics the effects of a 2d array?
Some basic tips would be much appreciated as I need to do an assignment that has a **ptr to imitate a 2d array and without knowing how it does this first means I can't even solve it on paper (for example, how do you dereference a **ptr, how do you get [x][y] values etc)
thanks
You can subscript a pointer the same way you can subscript an array, provided all the addresses have been set up correctly.
Assuming the following declaration:
char **ptr;
here are the types of the various expressions:
Expression Type Equivalent expressions (yield same value)
---------- ---- -----------------------------------------
ptr char ** &ptr[0]
*ptr char * ptr[0]
*(ptr+i) char * ptr[i]; &ptr[i][0]
**ptr char ptr[0][0]
*(*(ptr+i)) char ptr[i][0]; *ptr[i]
*(*(ptr+i)+j) char ptr[i][j]
thus:
ptr can be treated as though it was an array of strings (2-d array of char)
ptr[i] points to the beginning of the i'th string in the list
ptr[i][j] is the value of the j'th character of the i'th string in the list
The expressions ptr++ and ++ptr will advance ptr to point to the next string
The expressions (*ptr)++ and ++(*ptr) will advance *ptr to point to the next character
As for setting up your pointers, this arrangement assumes everything has already been allocated as static arrays or dynamically through malloc. You cannot just write
char **ptr = {"foo", "bar", "bletch"}; // using aggregate initializer on
// non-aggregate type; bad juju,
// a.k.a undefined behavior
or
char **ptr; // ptr has not been initialized to point anywhere
ptr[0] = "foo"; // dereferencing ptr via subscript invokes undefined
ptr[1] = "bar"; // behavior
ptr[2] = "bletch";
Generally, when you're using a pointer as though it was an array, you'll use malloc or something similar to allocate your buffers:
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
ptr[0] = "foo"; // ptr[i] gets address of
ptr[1] = "bar"; // string literal
ptr[2] = "bletch";
...
}
or
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
size_t i;
for (i = 0; i < N; i++)
{
ptr[i] = malloc(sizeof *ptr[i] * M); // strictly speaking, the sizeof
if (ptr[i]) // is not necessary here
{
//initialize ptr[i]
}
}
}
A pointer to a pointer is just that. For example:
// Declare our double-indirection pointer.
char** ptr;
// And initialize it:
char s1[] = "hello";
char s2[] = "world";
ptr = malloc(sizeof(char*) * 2);
ptr[0] = s1;
ptr[1] = s2;
// ptr now points to a pointer that points to 'h'.
char* ptr2 = *ptr;
// ptr2 points to 'h'.
char* ptr3 = *(ptr + 1);
// ptr3 points to "w".
char c = **ptr; // could be written as *(*ptr)
// c = 'h'.
char c2 = *(*(ptr + 1));
// c2 = 'w'.
char c3 = *(*(ptr) + 1);
// c3 = 'e'.
You may use them as you would a normal two-dimensional array. (Since effectively, that's what they are)
char** ptr = {"lorem", "ipsum", "dolor"};
char* s1 = ptr[0]; //Points to the beginning of "lorem"
char* s2 = ptr[1]; //Points to the beginning of "ipsum"
char c = ptr[2][4]; //Contains 'r'
This is due to the fact that:
int *a;
//...
int i = a[6];
int j = *(a + 6); //Same as previous line!
Cheers,
Amit Ron--