Reference to Array vs reference to array pointer - c

void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main(){
char array[10] = {'j','o','h','n'};
char * bla = array;
check(&bla);
check(&array);
}
Output:
word is john
RUN FINISHED; Segmentation fault; core dumped;
First one works, but second not. I don't understand why this happens.

The problem is, when we do &array, we are getting a char (*)[10] from an char [10], instead of a char **.
Before we do our experiment, I will emphasize that, when we pass an array as an argument to a function, C actually casts the array to a pointer. The big bucket of data is not copied.
Thus, int main(int argc, char **argv) is identical to int main(int argc, char *argv[]) in C.
This made it available for us to print the address of an array with a simple printf.
Let's do the experiment:
char array[] = "john";
printf("array: %p\n", array);
printf("&array: %p\n", &array);
// Output:
array: 0x7fff924eaae0
&array: 0x7fff924eaae0
After knowing this, let's dig into your code:
char array[10] = "john";
char *bla = array;
check(&bla);
check(&array);
bla is char *, and &bla is char **.
However, array is char [10], and &array is char (*)[10] instead of char **.
So when you pass &array as an argument, char (*)[10] acts like a char * when passing as an argument, as is said above.
Therefore **(char **) &bla == 'j' while *(char *) &array == 'j'. Do some simple experiments and you will prove it.
And you are casting void *elemAddr to a char ** and try to deference it. This will only work with &bla since it is char **. &array will cause a segfault because "john" is interpreted as an address as you do the cast.

For check(&bla); you are sending pointer to pointer
void check(void* elemAddr){
char* word = *((char**)elemAddr); // works fine for pointer to pointer
printf("word is %s\n",word);
}
This is working fine.
But, for check(&array); you are passing pointer only
void check(void* elemAddr){
char* word = *((char**)elemAddr); // This is not working for pointer
char* word = *(char (*)[10])(elemAddr); // Try this for [check(&array);]
printf("word is %s\n",word);
}
Full Code--
Code for check(array);:
void check(void* elemAddr){
char* word = *(char (*)[10])(elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
check((char*)array);
return 0;
}
Code for check(&bla);:
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
char* bla = array;
check(&bla);
return 0;
}

The C specification says that array and &array are the same pointer address.
Using the name of an array when passing an array to a function will automatically convert the argument to a pointer per the C specification (emphasis mine).
6.3.2.1-4
Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
So calling func(array) will cause a pointer to char[] to be passed to the function. But there is a special case for using the address-of operator on an array. Since array has type "array of type" it falls into the 'Otherwise' category of the specification (emphasis mine).
6.5.3.2-3
The unary & operator yields the address of its operand. If the operand
has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the
operand is the result of a unary * operator, neither that operator nor
the & operator is evaluated and the result is as if both were omitted,
except that the constraints on the operators still apply and the
result is not an lvalue. Similarly, if the operand is the result of a
[] operator, neither the & operator nor the unary * that is implied by
the [] is evaluated and the result is as if the & operator were
removed and the [] operator were changed to a + operator. Otherwise,
the result is a pointer to the object or function designated by its
operand
So calling func(&array) will still cause a single pointer to be passed to the function just like calling func(array) does since both array and &array are the same pointer value.
Common-sense would lead you to believe that &array is a double pointer to the first element of the array because using the & operator typically behaves that way. But arrays are different. So when you de-reference the passed array pointer as a double pointer to the array you get a Segmentation fault.

This is not a direct answer to your question, but it might be helpful to you in the future.
Arrays are not pointers:
type arr[10]:
An amount of sizeof(type)*10 bytes is used
The values of arr and &arr are necessarily identical
arr points to a valid memory address, but cannot be set to point to another memory address
type* ptr = arr:
An additional amount of sizeof(type*) bytes is used
The values of ptr and &ptr are typically different, unless you set ptr = (type*)&ptr
ptr can be set to point to both valid and invalid memory addresses, as many times as you will
As with regards to your question: &bla != bla == array == &array, and therefore &bla != &array.

One problem is that your char array is NOT NECESSARILY going to be null-terminated. Since array is an automatic variable that is allocated locally on the stack, it is not guaranteed to be zeroed-out memory. So, even though you are initializing the first 4 chars, the latter 6 are left undefined.
However ...
The simple answer to your question is that &bla != &array so your check() function is assuming it will find null-terminated character arrays at 2 different addresses.
The following equations are true:
array == &array // while not the same types exactly, these are equivalent pointers
array == bla
&array == bla
*bla == array[0]
&bla is never going to equal anything you want because that syntax references the address of the bla variable on the local stack and has nothing to do with its value (or what it points to).
Hope that helps.

Related

Pointer of Strings and Integers

I would like some help with pointer of strings and integers. If I intend to change the value of integers defined in the main function, it is necessary to pass the pointer of the variables otherwise nothing will be changed like: (a and b will swap to each other's original value)
void swapping(int *a,int *b){
int temp=0;
temp= *a;
*a=*b;
*b=temp;
}
int main(){
int a=1,b=2;
swapping(&a,&b);
printf("%d\n%d\n",a,b );
return 0;
}
However, when I continue on passing strings(char arrays), operations like this is feasible:
void split(char take1[],char take2[], char str[]){
int i=0,j=0,yes=0;
while(str[i]!='\0'){
if(str[i]=='*'){
yes=1;
i++;
}
if(yes==0){
take1[i]=str[i];
}
else if (yes!=0){
take2[j]=str[i];
j++;
}
i++;
}
}
int main(){
char taker1[30],taker2[30];
char str[30]="Hello*world";
split(taker1,taker2,str);
printf("%s\n%s\n",taker1,taker2) ;
return 0;
}
My shallow understanding is because functions that get called are temporarily stored in RAM, so the value reassigned in the function will be removed once the function call is finished. Thus, we need to change the value of pointer in the memory.
But I didn't get why there is no need to pass the pointer of the char arrays as in second example to the function(split()) to alter their values . Could someone please help to see why? Thanks!
(OP) But I didn't get why there is no need to pass the pointer of the char arrays as in second example to the function(split()) to alter their values .
With many operations1, arrays are converted to the pointer of the first element. That happened with
split(taker1,taker2,str);
Let's dig deeper.
The C standard library defines string
A string is a contiguous sequence of characters terminated by and including the first null character. C17dr § 7.1.1 1
char array str below contains a string.
char str[30]="Hello*world";
char arrays taker1, taker2 are uninitialized. They do not certainly contain a string.
char taker1[30],taker2[30];
(OP) I continue on passing strings(char arrays),
Not quite. Below, char array taker1 is converted to the address of the first element when passed to the function. Like-wise for taker2, str
split(taker1, taker2, str);
split() receives 3 pointers, even though it may look like arrays.
void split(char take1[],char take2[], char str[]){
// same as
void split(char *take1, char *take2, char *str) {
The body of split() then uses these pointers to manipulate data. Recall these pointers point to main's str[], taker1[], taker2[]. When splt() is done, printf("%s\n%s\n", taker1, taker2) ; shows the effect.
1 Except when it is the operand of the sizeof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type “array of type” is converted to an expression with type “pointer to type” that points to the initial element of the array object and is not an lvalue. C17dr
char take[] is essentially the same as char *take. So you actually passing the pointer.
In char taker[30] case for example taker itself is a pointer and taker[n] is equivalent to *(taker + n).
EXPLANATION
This is because, in C, an array declaration decays to a pointer internally (Refer to the citation at the end for details). When you declare char a[], it is the same as declaring char* a. In both of these cases, a stores the memory address of the first element of the array. But, in the case of variables like plain integers or characters, such as int x = 10;, the variable x will actually store the value 10.
When you declare an array such as
char a[10];
the object designated by the expression a is an array (i.e., a contiguous block of memory large enough to hold 10 character values a.k.a string), and the type of the expression a is an "array of 10 character elements", or char[10]. The expression a is implicitly converted to char *, and its value is the address of the first element.
Thus, when you pass an array variable to a function, you are actually passing the memory address (or base address) of the array. And since you have written your function declaration as:
void split(char take1[],char take2[], char str[])
It is the same as writing:
void split(char *take1,char *take2, char *str)
And, in your function call which is:
split(taker1,taker2,str);
taker1, taker2 and str actually contain base addresses of the respective character arrays (i.e. string). So you don't explicitly have to mention the address_of operator (&) along with the array variables in the function call.
The code you have posted can also be written as follows:
void split(char *take1,char *take2, char *str){
int i=0,j=0,yes=0;
while(*(str+i) != '\0'){
if(*(str+i) == '*'){
yes=1;
i++;
}
if(yes==0){
*(take1+i) = *(str+i);
}
else if (yes!=0){
*(take2+i) = *(str+i);
j++;
}
i++;
}
}
int main(){
char taker1[30], taker2[30];
char str[30] = "Hello*world";
split(taker1, taker2, str);
printf("%s\n%s\n", taker1, taker2) ;
return 0;
}
Notice the interchanged array operator([]) and and dereference operator(*). Hint: Writing arr[5] is the same as *(arr + 5).
LONG STORY SHORT:
In C, arrays are passed by reference. Normal variables are passed by value.
Array variables can be treated as pointers.
You ought to normally skip the & with array variables in function calls.
BONUS
The aforementioned reason is also why we don't use & in scanf() for string variables (with %s format specifier), i.e.,
char str[10];
scanf("%s", str);
But in the case of integers or other primaries:
int num;
scanf("%d", &num);
Also, you will get a better understanding of the concepts involved after going through dynamic memory allocation in C.
CITATION
Here's the exact language from the C standard (n1256):
6.3.2.1 Lvalues, arrays, and function designators ... 3 Except when it is the operand of the sizeof operator or the unary & operator or is a
string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type
‘‘pointer to type’’ that points to the initial element of the array
object and is not an lvalue. If the array object has register storage
class, the behavior is undefined.

How can I understand the concept of pointers (*) and address-of (&) operators?

I am trying to understand the significance of these two operators, so I wrote this code just for that purpose.
#include <stdio.h>
#include <string.h>
int main()
{
char *mnemonic, *operands;
mnemonic = "add";
operands = "five to two";
analyse_inst(mnemonic, operands);
}
void analyse_inst(char mnemonic, char operands)
{
printf("%s", mnemonic);
printf("%s", operands);
}
However, I noticed that it wouldn't work unless I change the arguments of analyse_inst() function to analyse_inst(char * mnemonic, char * operands), which means that I will be passing pointers to the function. But why is that required?
Also, I looked up about "passing by reference." And according to tutorialspoint.com, its definition:
The call by reference method of passing arguments to a function copies
the address of an argument into the formal parameter. Inside the
function, the address is used to access the actual argument used in
the call. It means the changes made to the parameter affect the passed
argument.
From that, I got that passing a variable by reference and then modifying that value would mean that the same variable outside the function would be changed as well; whereas for passing a variable by value would not change the same variable located outside the function.
Am I going wrong anywhere?
How can I can modify my code such that I am passing the two variables by reference?
(P.S. I have read other Stack Overflow threads on the same topic, but I would appreciate it if anyone could explain it in the context of the code I wrote)
which means that I will be passing pointers to the function. But why is that required?
Because what you have in main are pointers, and what printf("%s" expects is a char*.
"Pass by reference" is a broad term in programming, meaning passing along an address rather than a copy of the object. In your case, you pass a pointer to the first element of each string, rather than making a copy of the whole string, since that would waste execution time and memory.
So while the strings themselves could be said to be "passed by reference", strictly speaking C actually only allows parameters to be passed by value. The pointers themselves are passed by value. Your function parameters will be copies of the pointers you have allocated in main(). But they point at the same strings as the pointers in main() do.
From that, I got that passing a variable by reference and then modifying that value would mean that the same variable outside the function would be changed as well;
Indeed, you could change the string from inside the function through the pointer and then it would affect the string in main(). But in this case, you haven't allocated any memory to modify - you would attempt to modify a string literal "...", which would have been a bug. If you were to modify the strings, you should have declared them as arrays in main(): char mnemonic[] = "add";
Now as it turns out, whenever you use an array like the one in my example inside an expression, it "decays" into a pointer to the first element. So we wouldn't actually be able to pass the array by value to the function, as the C language would have changed it between the lines to a pointer to the first element.
You can play around with this code:
#include <stdio.h>
#include <string.h>
void analyse_inst(char* mnemonic, char* operands);
int main()
{
char mnemonic[] = "add";
char operands[] = "five to two";
analyse_inst(mnemonic, operands);
printf("%s\n", mnemonic);
}
void analyse_inst(char* mnemonic, char* operands)
{
printf("%s ", mnemonic);
printf("%s\n", operands);
strcpy(mnemonic, "hi");
}
When you write something like char *mnemonic that means you are creating a pointer variable (variable that will hold the address of another variable) but since the data type of the mnemonic is char it will hold the address of variable with char datatype only.
Now, inside your code you have written mnemonic = "add" so here "add" is the string that is array of characters and mnemonic is pointing to the base address of that array.
and while calling the function you are passing the references of these char arrays, so you need to change void analyse_inst(char mnemonic, char operands) to void analyse_inst(char *mnemonic, char *operands) to get the references in these respective pointer variables. Reason is same We need pointer variables to hold the references.
And the & returns the address of the variable, that means the reference to the memory location in which the variable is stored.
Hope this will help.
Strings in C are stored as arrays of characters, terminated by a character with the value '\0' ("NIL"). You cannot directly pass around arrays, so instead a pointer to the first character is used, which is why you must pass char *s to the function in order to access strings.
A character is typically much smaller than a pointer (think 8 vs 32/64 bits), so you cannot squeeze a pointer value into a single character.
C does not have pass by reference; it's pass by value only. Sometimes that value is as close to a reference as the language can come (i.e. a pointer), but then that pointer is in turn passed by value.
Consider this:
static void put_next(const char *s)
{
putchar(*s++);
}
int main(void)
{
const char *string = "hello";
put_next(string);
put_next(string);
}
This will print hh, since it's being passed the same value string every time, the fact that s, which is a different variable holding a copy of the same value, is incremented inside the function doesn't matter. The incremented value is local to the function, and thrown away once it goes out of scope.
I will discuss things in the context of your code, but I want to get some basics out of the way first.
In a declaration, the unary * operator indicates that the thing being declared has pointer type:
T *p; // for any type T, p has type "pointer to T"
T *p[N]; // for any type T, p has type "N-element array of pointer to T"
T (*p)[N]; // for any type T, p has type "pointer to N-element array of T"
T *f(); // for any type T, f has type "function returning pointer to T"
T (*f)(); // for any type T, f has type "pointer to function returning T"
The unary * operator has lower precedence then the postfix [] subscript and () function operators, so if you want a pointer to an array or a function, the * must be explicitly grouped with the identifier.
In an expression, the unary * operator dereferences the pointer, allowing us to access the pointed-to object or function:
int x;
int *p;
p = &x; // assign the address of x to p
*p = 10; // assigns 10 to x via p - int = int
After the above code has executed, the following are true:
p == &x // int * == int *
*p == x == 10 // int == int == int
The expressions p and &x have type int * (pointer to int), and their value is the (virtual) address of x. The expressions *p and x have type int, and their value is 10.
A valid1 object pointer value is obtained in one of three ways (function pointers are also a thing, but we won't get into them here):
using the unary & operator on an lvalue2 (p = &x;);
allocating dynamic memory via malloc(), calloc(), or realloc();
and, what is relevant for your code, using an array expression without a & or sizeof operator.
Except when it is the operand of the sizeof or unary & operator, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T", and the value of the expression is the address of the first element of the array3. So, if you create an array like
int a[10];
and pass that array expression as an argument to a function like
foo( a );
then before the function is called, the expression a is converted from type "10-element array of int" to "pointer to int", and the value of a is the address of a[0]. So what the function actually receives is a pointer value, not an array:
void foo( int *a ) { ... }
String literals like "add" and "five to two" are array expressions - "add" has type "4-element array of char" and "five to two" has type "12-element array of char" (an N-character string requires at least N+1 elements to store because of the string terminator).
In the statements
mnemonic = "add";
operands = "five to two";
neither string literal is the operand of the sizeof or unary & operators, and they're not being used to initialize a character array in a declaration, so both expressions are converted to type char * and their values are the addresses of the first element of each array. Both mnemonic and operands are declared as char *, so this is fine.
Since the types of mnemonic and operands are both char *, when you call
analyse_inst( mnemonic, operands );
the types of the function's formal arguments must also be char *:
void analyse_inst( char *mnemonic, char *operands )
{
...
}
As far as the "pass by reference" bit...
C passes all function arguments by value. That means the formal argument in the function definition is a different object in memory from the actual argument in the function call, and any changes made to the formal argument are not reflected in the actual argument. Suppose we write a swap function as:
int swap( int a, int b )
{
int tmp = a;
a = b;
b = tmp;
}
int main( void )
{
int x = 2;
int y = 3;
printf( "before swap: x = %d, y = %d\n", x, y );
swap( x, y );
printf( "after swap: x = %d, y = %d\n", x, y );
...
}
If you compile and run this code, you'll see that the values of x and y don't change after the call to swap - the changes to a and b had no effect on x and y, because they're different objects in memory.
In order for the swap function to work, we have to pass pointers to x and y:
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main( void )
{
...
swap( &x, &y );
...
}
In this case, the expressions *a and *b in swap refer to the same objects as the expressions x and y in main, so the changes to *a and *b are reflected in x and y:
a == &x, b == &y
*a == x, *b == y
So, in general:
void foo( T *ptr ) // for any non-array type T
{
*ptr = new_value(); // write a new value to the object `ptr` points to
}
void bar( void )
{
T var;
foo( &var ); // write a new value to var
}
This is also true for pointer types - replace T with a pointer type P *, and we get the following:
void foo( P **ptr ) // for any non-array type T
{
*ptr = new_value(); // write a new value to the object `ptr` points to
}
void bar( void )
{
P *var;
foo( &var ); // write a new value to var
}
In this case, var stores a pointer value. If we want to write a new pointer value to var through foo, then we must still pass a pointer to var as the argument. Since var has type P *, then the expression &var has type P **.
A pointer value is valid if it points to an object within that object's lifetime.
An lvalue is an expression that refers to an object such that the object's value may be read or modified.
Believe it or not there is a good reason for this rule, but it means that array expressions lose their "array-ness" under most circumstances, leading to much confusion among people first learning the language.

Confusing on pointer array

The following is the C code:
char *ptr[100];
printf("%s\n",*ptr++);
My question is: we know that array name is not a variable (Ritchie's book "The C programming language" Page 99), so if we define
int *pa,a[5];
This is legal:
pa = a; pa++;
while this is illegal:
a++;
Here char *ptr[100] defines a char pointer array, so ptr represents the initial address of the array. For the above code, if *ptr++ means *(ptr++), this is illegal because array name cannot be used as a variable, and also it's meaningless because *(ptr++) still gets an address as opposed to %s. However, if *ptr++ means (*ptr)++, it also looks strange... Can anyone help to understand this?
The above is my thinking process, my question is: how can *ptr++ give us a string as the code printf("%s\n",*ptr++); says?
Postfix increment ++ has a higher precedence than dereference *.
Thus, *ptr++ is interpreted as *(ptr++). And as you've correctly figured out, ptr++ isn't allowed if ptr is an array (of anything, values or pointers).
If ptr is a pointer, then *ptr++ will indeed increment the pointer (so it will point to the next value after the operation), and this expression will return the current pointed-to value (before increment of the pointer). This expression is indeed sometimes used, e.g. for copying memory areas, e.g.:
while (...) {
*dest++ = *src++; // Copy the current element, then increment both pointers
}
*ptr++ doesn't necessarily give you a string — it gives you a string if and only if ptr is pointing to a string. And in this case, it's not necessary to post-increment just to get the string — *ptr would be enough. ++ is done for another purpose.
For example, it ptr is a pointer to an "array" of strings (i.e. a pointer to a pointer to achar, i.e. char **ptr), then you could print all the strings like this:
int i;
for (i = 0; i < N; ++i) {
printf("%s\n",*ptr++); // '++' "jumps" to the next string
}
I believe this link should help you.
C/C++ int[] vs int* (pointers vs. array notation). What is the difference?
The array notation has a bounds limit while the pointer notation does not.
If you wanted to access the next in the array with array notation it would look something like a[n++] n being whatever the current index of the array you are at. Where as assigning ptr to a sets ptr to the first index of the array and you can increment a pointer.
*ptr++ is parsed as *(ptr++) - apply the ++ operator to ptr, then dereference the result.
As written, this results in a constraint violation - ptr is an array of pointers to char, and an expression of array type is a non-modifiable lvalue, and as such may not be the target of an assignment or the operand of the ++ and -- operators.
The line
printf("%s\n",*ptr++);
should (indeed, must) result in the compiler issuing a diagnostic on the order of "invalid lvalue in increment" or something along those lines.
No. 1:
void main(void)
{
int i;
char *ptr[3]={"how","are","you"};
for (i=0;i<3;i++)
printf("%s\n",ptr[i]);
}
This prints out correct answer. Good!
No.2:
void main(void)
{
int i;
char *ptr[3];
*ptr[0] = "how";
*ptr[1] = "are";
*ptr[2] = "you";
for (i=0;i<3;i++)
printf("%s\n",ptr[i]);
}
warning: assignment makes integer from pointer without a cast [enabled by default].....Why can't initialize like this?
No.3:
void main(void)
{
int i;
char *ptr[3]={"how","are","you"};
printf("%s\n",*ptr++);
}
error: lvalue required as increment operand....Why can't we use *ptr++?

Why isn't this pointer arithmetic allowed in C? [duplicate]

This question already has answers here:
Is array name a constant pointer in C++?
(2 answers)
Closed 6 years ago.
char arr[] = "Hello";
arr = arr + 1; // error occurs
As far as I know, an expression that has array type is converted to pointer type that points to the initial element of the array. Therefore, I expected arr = arr + 1 (pointer to first element(arr) of the array becomes the pointer to the second element of the array)to work. Why doesn't this work in C?
arr + 1 is indeed a pointer to the second element of the array (i.e. &arr[1]).
However, that does not mean that you can somehow write that pointer value back into arr. You can't do it for at least two reasons.
Firstly, arr is an array of char elements, not a pointer. There's an obvious type mismatch here.
Secondly, being an array, arr a non-modifiable lvalue. You cannot change arr itself, you can only change its elements (this distinction is somewhat hard to grasp, but it is there).
Finally, if we just ignore the deeper intricacies and focus on what formally happens at the top level, due to array type decay your expression is equivalent to
(char *) arr = (char *) arr + 1;
The assignment is impossible since the left-hand side is a result of [implicit] type conversion. In C type conversions always produce rvalues. You cannot assign to rvalues.
In other words, it is not the "pointer arithmetic" that's disallowed here. The pointer arithmetic is fine. It is what you do with the result of that pointer arithmetic that causes the error.
Arrays are non-modifiable lvalues. They can't be the left operand of an assignment operator.
C11-§6.3.2.1:
A modifiable lvalue is an lvalue that
does not have array type, does not have an incomplete type, [...]
§6.5.16/2:
An assignment operator shall have a modifiable lvalue as its left operand.
In the statement
arr = arr + 1;
arr is the left operand of = operator and is of array type. It can't be modified.
So, it's not the pointer arithmetic but the constraint by the language on the assignment operator that is the reason for syntactical error.
Note that in some contexts arrays decay to a pointer to its first element, though pointers and arrays are different types. Arrays are not pointers. It is only the pointer arithmetic and array indexing which are equivalent. For example
char *ptr = &arr[0] + 1 => &(*(arr + 0)) + 1 => &(*arr) + 1 => arr + 1 // * and & nullify each other
This is because arrays are similar to pointers except that they can not be modified. However you can modify a pointer that is pointing to an array. For the above example you can do like this:
char arr[]="Hello";
char *ptr=arr;
ptr=ptr+1;
Initially the pointer ptr will be pointing to the first character of the array i.e. 'H' and after modifying the value it will point to the second character i.e. 'e'. You can also do the following:
char arr[]="Hello";
char *ptr=arr;
ptr=arr+1;
Both produce the same effect which shows that arr+1 is indeed pointer arithmetic. However you can not modify the value of arr because its type is that of a character array and not pointer to a character array.
As far as I know, an expression that has array type is converted to pointer type that points to the inital element of the array.
It is true in most contexts. It is not true in the following contexts:
When using the addressof operator (&arr). The type of &arr is char (*)[6]. It is not char**.
When using the sizeof operator. sizeof(arr) is 6. Had it been a pointer, it would be the size of a pointer (4 or 8 in most common platforms).
When used as the LHS of an assignment operator. A variable of array type is not modifiable.
Therefore, I expected arr = arr + 1 (pointer to first element(arr) of the array becomes the pointer to the second element of the array)to work. Why doens't this work in C?
The RHS of the expression evaluates to a pointer to the second element of arr. However, that line does not work due to (3) above. arr is not a modifiable value. It cannot be used as the LHS of an assignment operator.
char[] is not pointer, while char* is a pointer.
This works, but it is wrong solution:
int main()
{
char *arr = "Hello";
arr = arr + 1; // Wrong!
printf("%s\n", arr); // Output: ello
}
If arr is heap-allocated with malloc you can get memory leak if free memory starting arr+1 not arr.
But you can do something like this:
int main()
{
char arr[] = "Hello";
char *wordFromSecondLetter = &arr[0] + 1;
printf("%s\n", wordFromSecondLetter); // Output: ello
}
Or like this
int main()
{
char arr[] = "Hello";
printf("%s\n", &arr[1]); // Output: ello
}
Because arr is not a pointer but a char array. You can verify this by checking sizeof arr. To get a pointer to char, you should use char *arr = "Hello";.
The biggest difference between a pointer and an array is that you can directly assign a value to a pointer, but you can't do this to an array.
In fact, when you write arr + 1, arr "decays" to the pointer to its first element, that is to say, arr == &arr[0]. So arr + 1 is legal pointer arithmetic, but giving its value to arr, which is an array, is illegal.

referencing an index value of a character in a pointer string in c

Suppose I have something like this
int strLen;
printf("Please enter a number: ");
scanf("%d", &strLen);
char *myString;
myString = (char*) malloc(strLen*sizeof(char));
then you fill string with something like "Hello World!" but now I want to just print out "World!" Since my string is just a pointer reference, I can't call it out by indexes ie.
for(int i=6;i<strLen;i++)
{
printf("%s", myString[i]);
}
// THIS IS AN INCORRECT WAY TO DO THIS
How could I refer to a specific character or even pass the array onto another function of the program if all I have is the array base pointer? Can I ever get the full functionality as if I declared it as a static array before compile time?
How could I refer to a specific character or even pass the array onto another function of the program if all I have is the array base pointer?
Several things to remember:
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 replaced with ("decay to") an expression of type "pointer to T" whose value is the address of the first element of the array;
In the context of a function parameter declaration, T a[N] and T a[] are identical to T *a (IOW, a will be declared as a pointer to T, not an array of T - note that this is only true for function parameter declarations);
The subscript operation a[i] is defined as *(a + i) - start with a base address specified by the pointer expression a, offset by i elements (not bytes), and dereference the result;
In C, you do not need to cast the result of malloc (or calloc or realloc), since it returns a value of type void *, which may be assigned to any other object pointer type. Adding the cast may suppress a useful diagnostic if you forget to include stdlib.h or otherwise don't have a prototype in scope. Note that this is not true for C++ - a cast is required there, but if you're writing C++ you should be using new instead of malloc anyway.
This is a long-winded way of saying that, in many contexts, array expressions and pointer expressions can be treated the same way. Taking printf as an example:
int main(void)
{
char foo[] = "This is a test";
char *bar = foo;
printf("%s\n", foo);
printf("%s\n", &foo[0]);
printf("%s\n", bar);
return 0;
}
printf expects the argument corresponding to %s to have type char *, or "pointer to char", not "array of char". The three printf calls above are all equivalent. In the first call, foo is an array expression with type "15-element array of char". By the first rule mentioned above, it will be replaced with an expression of type "pointer to char" whose value is the address of the first element. The second and third calls pass the pointer value directly, just using different expressions to accomplish the same effect.
As far as printf is concerned, all three expressions yield the same result -- the address of the first element of a sequence of char values, terminated by 0.
What does this mean for your code? Well, for one thing, you can use the subscript operator on mystring as though it were an array type:
printf("%s\n", &mystring[6]); // prints "World!"
Note that the subscript operator [] has higher precedence than the unary & operator, so the above is interpreted as &(mystring[6]) - we subscript into mystring and then take the address of the result.
You can pass mystring to any function that you would pass an array of char to:
void foo(char str[]) // identical to char *str
{
// do something with str
}
...
int main(void)
{
char str[] = "Hello, World!";
char *mystr = malloc(strlen(str) + 1); // note no cast
strcpy(mystr, str);
foo(str);
foo(mystr);
...
}
Again, as far as the function foo is concerned, its argument is type char *, not array of char. The expression str decays to a pointer value, and mystr is a pointer value to begin with.
A couple of things:
1) Allow for the null terminator in your "malloc()":
int strLen;
...
char *myString = (char*) malloc(strLen+1);
2) The "sizeof(char)" is kind of duplicate redundant. No harm - but no purpose, either. So I omitted it.
3) This is wrong:
for(int i=6;i<strLen;i++)
{
printf("%s", myString[i]);
}
4) This is better:
for(int i=6;i<strLen;i++)
{
printf("%c", myString[i]);
}
You can take the address of the character at a certain array index.
So, try this if you just want to print out 'world!':
#include <stdio.h>
int main(int a, char** b)
{
int strLen;
char *myString;
myString = "hello world!";
printf("%s", &myString[6]);
return 0;
}

Resources