Why does this C array reference look incorrect? - c

Below is a piece of code copied from a website.
The value set for the direction prints the respective character from "nsew". For example the output of this code is character w.
I am wondering how does it work.
#include<stdio.h>
void main (void){
int direction = 3;
char direction_name = direction["nsew"];
printf("%c",direction_name);
}

This is because the array subscript operator is commutative, i.e., this:
const char *p = "Hello";
char x = p[0];
Is equivalent to
const char *p = "Hello";
char x = 0[p];
Weird, huh? In your case you are indexing into the third position of the string literal (which is an array) "nsew".
some_ptr[n] is equivalent to *(some_ptr + n), and since addition is commutative, it is also equivalent to *(n + some_ptr). It then follows that n[some_ptr] is also an equivalent expression.
I wouldn't recommend using this "feature" however... seriously, don't do it.

Operator [] has the same semantics as pointer arithmetics. So a[i] is equivalent to *(a + i) which is equivalent to *(i + a) which is equivalent to i[a]:
So direction["nsew"] == "nsew"[direction] == "nsew"[3] == 'w'

Related

Pointer or address?

// Capitalizes a copy of a string while checking for errors
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// Get a string
char *s = get_string("s: "); //this is in the cs50.h
char *t = malloc((strlen(s) + 1) * sizeof(char));
// Copy string into memory
for (int i = 0, n = strlen(s); i <= n; i++)
t[i] = s[i];
return 0;
}
The above code is from cs50 2018 lecture #3 . t[i] = s[i] part confused me. As I know, when we say char *t , t will store the address of the first part of the memory that was allocated. So doesn't t[i] give us the address of the memory at t[i] location ? If it is like so, shouldn't we write
*t[i] = s[i] to change the value of t[i] ?
No, the [] array index operator dereferences the pointer and evaluates to the value itself, not its address. The expression s[i] is equivalent to the expression *(s + i). If you wanted the address of the element at index i, you would need to use the & operator, as in &s[i] (which is equivalent to s + i).
int array[] = { 10, 20, 30, 40 }; // create an array for illustration
int *ptr = array; // array type decays to a pointer
// these print the same thing: the address of the array element at index 2
printf("%p\n", ptr + 2); // pointer arithmetic
printf("%p\n", &ptr[2]); // array index operator followed by address-of operator
// these print the same thing: the element at index 2 (= 30)
printf("%d\n", *(ptr + 2)); // pointer arithmetic followed by dereference operator
printf("%d\n", ptr[2]); // array index operator
t[i] actually gives you the ith element of the array. It works the same as s[i], which has the same type.
The syntax t[i] is exactly the same as *(t + i). In other words, pointer arithmetic is performed to get a pointer to the desired element, then the result is dereferenced to get the actual element.
char *s = ...;
char *t = ...;
...
t[i] = s[i];
t[i] is an lvalue, an expression that refers to an object. Oversimplifying a bit [*], if it appears on the left side of an assignment (as it does here), it refers to a particular char object, and the assignment updates the value of that object. s[i] is similar, but it appears on the right side of the assignment, so it yields the value of the object.
It's essentially the same thing as:
int x;
int y;
y = x;
x and y are both names of objects, and they're both lvalues. The y on the left hand side refers to the object. The x on the right hand side yields the value stored in the object.
[*] The oversimplification is that there are contexts other than the left hand side of an assignment in which an lvalue refers to an object rather than yielding its value.
There's a bit more going on here in the way the [] operator is defined (see the comp.lang.c FAQ) section 6 for the relationship between arrays and pointers), but in this case all you really need to know is that s[i] and t[i] are the names of objects.
The gory details are in the C standard, N1570 draft, section 6.3.2.1.

C Language Pointer Memory?

int num = 78;
int *p;
int array[SIZE] = {0,1,2,3,4};
char c[SIZE] = {'A', 'B', 'C', 'D', 'E'};
p = array[3];
*p = (int) *c;
p++;
array[4] = num;
p++;
p = c;
p++;
I'm trying to figure out the memory behind this above code. I understand that the pointer p initially points to the 3rd element of the array(which is 3). I have no idea what the next line *p = (int) *c; means. Can anyone please explain that line of code??
Edit:
After the p is incremented as such can anyone explain what it would be pointing to?
You should use 'p = &array[3];'. The pointer will then point to the third element of the array i.e. 'C'
*p = (int) *c;
c[size] is an array. c is the base pointer of the array. so *c is the value at the base pointer which is 'A'. This statement will put 'A' in the third element of the array. So the array now contains A, B, A, D, E
p = array[3]; // int * = int
is an error; the types don't match, and the compiler will yell at you for it. The type of p is int *, and the type of array[3] is int.
There are two ways to fix this, depending on what you want to do. If you want to set p to point to array[3] (which is what you want to do in this case), you would write
p = &array[3]; // int * = int *
If you want to write the value of array[3] to the object that p points to (which is not what you want to do in this case, since p isn't pointing anywhere valid yet), you would write
*p = array[3]; // int = int
In this case, we want to set p to point to array[3], so we use the first statement. After doing that, the following are true:
p == &array[3] // int *
*p == array[3] == 2 // int
Now we have the statement
*p = (int) *c;
is saying "take the value of the char object that c points to, convert it to an int value1, and assign the result to the object that p points to."
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an array of char 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 of the array.
The expression c has type "5-element array of char". Since it is not the operand of the sizeof or unary & operators, it is converted to an expression of type char *, and the value of the expression is the address of the first element in the array, c[0]. Thus:
c == &c[0] // char *
*c == c[0] == 'A' == 65 (ASCII) // char
Taking all that together, that means
*p = (int) *c;
is another way of writing
*p = (int) c[0];
which is another way of writing
array[3] = (int) c[0];
which is another way of writing
array[3] = (int) 'A';
which is another way of writing
array[3] = 65;
(int) is a cast expression; it means that the value following it should be treated as type int.
*p = (int) *c;
*c means that you take the value at the address of c
(int) casts it to an int
*p= writes to the address p points to
So if you fix what droppy said, there will be the numerical value of c[0] in the 3rd part of array
so it would be 1,2,65,4,5

C Putting code in one liner

I'm learning C and this is probably the most stupid question ever but here it goes!
My code:
char tmp = *x++;
char *g = &tmp;
Can I do this line of code in a one liner? With something like:
char *g = &(*x++);
More info:
char *x = "1234";
//Turn each 'number' to a int
while(*x != '\0'){
char tmp = *x++;
char *x = &tmp;
int t = atoi(x);
}
If x is a pointer to char (and points to an existing object), then the declaration char *g = &(*x++); is allowed in standard C and has defined behavior.
The result of the * operator is an lvalue, per C 2011 6.5.3.2 4, so its address may be taken with &.
In detail:
x++ increments x and produces the original value of x. (Note: Incrementing a pointer requires that the pointer point to an object. It does not require that it be an array element or that there be another object after it; you are allowed to increment to point one past an object, as long as you do not then dereference a pointer to a non-existent object.)
*x++ dereferences the pointer (the original value of x). The result is an lvalue.
&(*x++) takes the address of the lvalue, which is the original value of x.
Then this value is used to initialize g.
Additionally, C 2011 6.5.3.2 3 specifies that the combination of & and * cancel, except that the result is not an lvalue and the usual constraints apply, so the & and * operations are not actually evaluated. Thus, this statement is the same as char *g = x++;.
Just as a hint: Are you aware that you are shadowing the outer x variable?
What you are currently doing is:
char *x = "1234"; //declare c style string
while(*x != '\0'){ //for the conditional the "outer" x will be used for comparsion
char tmp = *x++; //increment x to point to whatever comes sizint atoi (const char * str);eof(char) bytes afterwards; dereference what x previously pointed to (postfix ++) and save it in local char tmp
char *x = &tmp; //take adress of the local char and save its adress in a new local/inner char*
int t = atoi(x); //call atoi on the inner x
Although this may work it may be confusing style to shadow variables like this. (Confusing for other developers especially)
Also take a look at the signature of atoi:
int atoi (const char * str);
Here you can see that you can safely pass the pointer like this:
int t = atoi(&x);
++x;
Or preferably:
int t = atoi(&x++);

Arrays & pointers in C

So I have the following code snippet:
#include <stdio.h>
void pointer_shift(int *a, int n);
int main(void) {
int a[] = {100, 101, 102};
pointer_shift(a1, 3);
}
void pointer_shift(int *a, int n) {
int i;
for (i = 0; i != n - 1; i++) {
*(a + i) = *(a + i + 1);
}
}
I just want to clarify how the pointers work in this snippet. So pointer_shift takes in 'a', a pointer to an int, correct? a1 is passed in to this parameter, and since arrays decay to a pointer to their first element, it works.
First of all, hopefully what I said in the above paragraph is correct. Secondly, what does *(a + i) = *(a + i + 1); actually do? Say we're on the first iteration of the for loop, and i = 0. Then the left side, *a, accesses what, exactly? Does it represent a pointer? I thought * was the dereferencing operator, and accesses the object that a pointer points to... And so then it sets *a = *(a + 1). (a + 1) is the next element in the array, but what exactly does this assignment do, and why?
Thanks!
It is actually not pointer shift, but value shift, *(a+i) is of same effect as a[i], so what it does is a[i] = a[i+1]
*(a + i) = *(a + i + 1); is copying array elements within the array using a bit of pointer arithmetic.
*(a + i) is equivalent to a[i], so the statement is equivalent to a[i] = a[i + 1];. The loop is moving the array values "to the left" in the array: a[0] = a[1]; a[1] = a[2]; and so on.
Your understanding of the function call is correct.
I just want to clarify how the pointers work in this snippet. So pointer_shift takes in 'a', a pointer to an int, correct? a1 is passed in to this parameter, and since arrays decay to a pointer to their first element, it works.
Yes, when you pass an array to a function it degrades to a pointer. An array is not a pointer in an object sense, but it is a pointer in a value sense. When you pass it to a function its value is passed, i.e., a pointer to the first element.
array indexing is the same as pointer arithmetic, so the last two lines in this snippet are equivalent:
int arr[] = {1, 2, 3};
arr[0] = 10;
*arr = 10;
as are these:
arr[1] = 20;
*(arr + 1) = 20;
The expression a + i is pointer arithmetic, incrementing the memory address stored in a by i units of the pointer size of a. So if a pointer to an int takes four bytes on your system, and if the current memory address is, say, 0x1234 the value of a + 1 would be 0x1238.
What the asterisk does is dereference that address and access the actual value at that address. If you have 100 stored at a or a[0], and 101 stored at a + 1 or a[1], then *(a + i) = *(a + i + 1) replaces 100 with 101 at a[0], for i = 0.
Basically, you want to read this C tutorial on pointers and arrays.

Pointer arithmetic C and casting

I've seen a very strange code snippet and i am not quite sure if i understood it right:
#include <stdio.h>
int main(char *argc, char **argv)
{
char a[50];
*(char *) (a + 2) = 'b'; // <== THE LINE WHICH CONFUSES ME
printf("value: %c\n", a[2]);
return 1;
}
Is it right that we go 2 buckets further cast the 'b' into a pointer to the b and then dereference it?
That's exactly equivalent of
*(a + 2) = 'b';
The cast is unnecessary.
All it does is add two to the array-which-decays-to-a-pointer a, dereference the resulting pointer, and assign the character 'b' to that memory location.
When a is a pointer, the code a[x] is exactly equivalent of *(a + x). So in your case, *(a + 2) = 'b' is exactly the same as a[2] = 'b'.
*(char *) (a + 2)
is equivalent to
a[2]
By definition, a[2] is *(a + 2). The value of a + 2 is already of type char * so a cast of a + 2 to char *, as is (char *) (a + 2), is a no operation.
*(char *) (a + 2) = 'b'; // <== THE LINE WHICH CONFUSES ME
This line literally means the very same as
a[2] = 'b'
The first cast (char*) is redundant, since a is already of type char. And indexing in fact translates to addition and dereferenciation, i.e.
a[n] === *(a + n)
A little known fact about C: You could write as well
n[a]
and get the same result.
You aren't casting the 'b'.
You cast (a+2) to char* (Which does nothing, since it's already char*), deference it, and put there 'b'.
And yes, it is right that we go 2 buckets further.
No, you treat a as a pointer, increment it by two, then cast it to (char*) (useless cast, it already is char*), dereference it and then store 'b' into that.
It is exactly the same as this:
a[2] = 'b';

Resources