Different way of accessing array elements in C - c

I am a teaching assistant for a C programming course, and I came across the following line of C code:
char str[] = "My cat's name is Wiggles.";
printf("%c %c %c %c\n", str[5], *(str + 5), *(5 + str), 5[str]);
I never came across the very last argument (5[str]) before, and neither did my professor. I don't think it's mentioned in K&R and C Primer Plus. I found this piece of code in a set of technical interview questions. Does anyone know why C allows you to access an array element that way also? I never heard of an index being outside the set of brackets and the name of an array inside the brackets.
Your help will be greatly appreciated!

Perfectly valid C. From Wikipedia:
Similarly, since the expression a[i] is semantically equivalent to *(a+i), which in turn is equivalent to *(i+a), the expression can also be written as i[a] (although this form is rarely used).
Wacky, but valid.

str[5] directly translates to *(str + 5), and 5[str] directly translates to *(5 + str). Same thing =)

It's basically just the way C works. str[5] is really equivelent to *(str + 5). Since str + 5 and 5 + str are the same, this means that you can also do *(5 + str), or 5[str].
It helps if you don't think of "5" as an index, but rather just that addition in C is commutative.

Similarly, since the expression a[i] is semantically equivalent to *(a+i), which in turn is equivalent to *(i+a), the expression can also be written as i[a] (although this form is rarely used).
http://en.wikipedia.org/wiki/C_syntax#Accessing_elements

Its all same. *ptr or ptr[0] actually means *(ptr+0). So whenever you write *ptr or ptr[0] it goes as *(ptr+0). Let say you want value at ptr[4] so it means you can also write it as *(ptr+4). Now whether you write it as *(ptr+4) or *(4+ptr), it's same. so just for understading if you can write *(ptr+4) as ptr[4] same way *(4+ptr) is same as 4[ptr]. Please go through http://en.wikipedia.org/wiki/C_syntax#Accessing_elements for more details.

if str is an array of type char, then we can access any index say i as below-
str[i]
*(str + i)
char *p = str, then access the index i as p[i] or *(p+i)

It's a funky syntax for sure, but...
str[5] would mean *(str+5)
And
5[str] would mean *(5+str)

Example Code.
#include<stdio.h>
int main(){
int arr[] = {1, 2, 3};
for(int i = 0; i <= 2; i++){
printf("%d\t", i[arr]);
}
return 0;
}
Output:1 2 3

Related

How does the C expression s[i ++] = t[j ++] exactly work in order?

I'm new in C, stuck in understanding the expression s[i ++] = t[j ++], I don't know how it's possible that an array element gets accessed with a variable and then the variable increase itself and then the array element just accessed is again accessed with the original variable and then gets assigned to another array's element, I'm confused, I think to understand the exact process might involve some low-level knowledges, but I don't want to digress too far away, is there any way to understand it easily and clearly?
In C language, the expression i++ causes i to be incremented, but the expression i++ itself evaluates to the value i had before being incremented. So the expression s[i++] = t[j++] has the same behaviour as:
s[i] = t[j];
i = i + 1;
j = j + 1;
except that the precise order is not specified. For that last reason, the rule is that a variable should only be modified once: s[i++] = t[i++] would invoke Undefined Behaviour.
Like any other complicated-looking expression, it's easier to understand this if you break it down into parts.
The key is that innermost part (or "subexpression") i++. I assume you know what i++ does by itself, although in this example, we're hopefully going to get a deeper appreciation of what i++ is actually good for. Why would you want to "increment i, but return the old value"? What's the use of this? Well, the main use is that it's super useful for moving along an array.
Lets look at a simpler example. Suppose we have an array a that we want to store some numbers in. The most basic way is
int a[10];
a[0] = 12;
a[1] = 34;
a[2] = 5678;
Another very good way is to use a second variable like i to keep track of where we're storing:
i = 0;
a[i] = 12;
i = i + 1;
a[i] = 34;
i = i + 1;
a[i] = 5678;
i = i + 1;
I've written this out in "longhand", but of course in C, you would almost never write it this way, because the "C way" is the much more concise
i = 0;
a[i++] = 12;
a[i++] = 34;
a[i++] = 5678;
So first, make sure you understand that the "shorthand" and "longhand" forms work exactly the same way. Make sure you understand that when we say something like
a[i++] = 34;
what this means is "store 34 into the slot in array a indicated by i, and then update i to be one more than is used to be, so that it indicates the next slot."
In other words, we use an expression like a[i++] whenever we want to move along an array and do something with its elements, one by one, in order.
So far we were storing values into the array, but the idiom works just as well for fetching values out of an array. For example, this code prints those three elements, again one at a time, in order:
i = 0;
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
My point is, again, that any time you see an expression like a[i++], you should think "we're moving along the array".
So now, finally, we can look at the expression you initially asked about:
s[i++] = t[j++];
Here we have two instances of the idiom. We're using i to move along the array s, and we're using j to move along the array t. We're fetching from t as we move along, and we're storing the values into s.
I don't know whether s and t are arrays of characters, or integers, or what. Also I don't know that s and t are truly arrays -- they might actually be pointers, pointing into some arrays. But I don't really have to know those things to know that the essential meaning of s[i++] = t[j++] is "copy elements from array t to array s, using j to keep where we are in t, and i to keep track of where we are in s".
[The above is an answer to your original question. The rest of this answer isn't directly related, but is essential to avoid inadvertently writing incorrect programs using ++ and --.]
As I said, the subexpression i++ and the idiom a[i++] are super useful for moving through arrays. But there are a couple things to beware of. (Actually it's just one thing, but it crops up in lots of different ways.)
Earlier I wrote the code
i = 0;
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
to print the first three elements of the array a. But it prints them as bare, isolated numbers. What if I want to always see which array index each number comes from? That is, what if I'm tempted to write something like this:
i = 0;
printf("%d: %d\n", i, a[i++]); /* WRONG */
printf("%d: %d\n", i, a[i++]); /* WRONG */
printf("%d: %d\n", i, a[i++]); /* WRONG */
If I wrote this, my intent would be that I would see the obvious display
0: 12
1: 34
2: 56788
But when I actually tried it just now, I got this instead:
1: 12
2: 34
3: 5678
The numbers 12 and 34 and 5678 are right, but the indices 1, 2, and 3 are all wrong -- they're off by one! How did that happen?
And the answer is that although i++ is, as I said, "super useful", it turns out that there's a fine line between "super useful" and what's called undefined behavior.
That printf call
printf("%d: %d\n", i, a[i++]); /* WRONG */
looks fine, but it's not actually well-defined, because the compiler does not necessarily evaluate everything left-to-right, so it's not actually guaranteed that it will use the old value of i for the %d: part. The compiler might evaluate things from right to left, meaning that a[i++] will happen first, meaning that %d: will print the new value, instead -- which appears to be what happened when I tried it.
Here's another potential issue. Your original question was about
s[i++] = t[j++];
which, as we've seen, copies elements from t to s based on two possibly-different indices i and j. But what if we know we always want to copy t[1] to s[1], t[2] to s[2], t[3] to s[3], etc.? That is, what if we know that i and j will always be the same, so we don't even need separate i and j variables? How would we write that? Our first try might be
s[i++] = t[i++]; /* WRONG */
but that can't be right, because now we're incrementing i twice, and we'll probably do something totally broken like copying t[1] to s[2] and t[3] to s[4]. But if we want to only increment i once, should it be
s[i++] = t[i]; /* WRONG */
or
s[i] = t[i++]; /* WRONG */
But the answer is that neither of these will work. In expressions like these, which have i in one place and i++ in the other place, there's no way to tell whether i gets the old value or the new value. (In particular, there's no left-to-right or right-to-left rule that would tell us.)
So although expressions like i++ and a[i++] are indeed super useful, you have to be careful when you use them, to make sure you don't go over the edge and have too much happening at once, such that the evaluation order becomes undefined. Sometimes this means you have to back off, and not use the "super useful" idiom, after all. For example, a safe way to print those values would be
printf("%d: %d\n", i, a[i]); i++;
printf("%d: %d\n", i, a[i]); i++;
printf("%d: %d\n", i, a[i]); i++;
and a safe way to copy from t[1] to s[i] would be
s[i] = t[i]; i++;
You can read more in this answer about how to recognize well-defined expressions involving ++ and --, and how to avoid the undefined ones.
The evaluations of s[i++] and t[j++] are unsequenced relative to each other. Semantically, it's equivalent to:
t1 = i;
t2 = j;
s[t1] = t[t2];
i = i + 1;
j = j + 1;
with the caveat that the last three assignments can happen in any order, even simultaneously (either in parallel or interleaved)1. The compiler doesn't have to create temporaries, either - the whole thing can be evaluated as
s[i] = t[j];
i = i + 1;
j = j + 1;
Alternately, the side effects of i++ and j++ can be applied before the update to s:
t1 = j;
j = j + 1;
t2 = i;
i = i + 1;
s[t2] = t[t1];
The current values of i and j must be known before you can index into the arrays, and the value of t[j] must be known before it can be assigned to s[i], but beyond that there's no fixed order of evaluation or of the application of side effects.
This is why expressions like x = x++ or a = b++ * b++ or a[i] = i++ all invoke undefined behavior - there's no fixed order for evaluating or applying side effects, so the results can vary by compiler, compiler settings, even by the surrounding code, and the results don't have to be consistent from run to run.

Can't understand &(sizeof 2[a])[a]

I've got some code that outputs bcdefg and I can't understand why.
I google searched but I couldn't find anything.
const char a[]="Abcdefg";
printf("%s",&(sizeof 2[a])[a]);
Why is the output bcdefg, and not Abcdefg?
This code is meant to confuse you, not do anything useful. Don't write code like this. Here is how it is interpreted by the compiler:
2[a] is the same as a[2], which is a value of char type (which value exactly doesn't matter; the compiler even doesn't try to evaluate it)
sizeof 2[a] is the same as sizeof(char), which is equal to 1
&(sizeof 2[a])[a] is a pointer to the character b in the string Abcdef - the one which has the index 1
printf("%s",&(sizeof 2[a])[a]) prints the string, starting at that pointer
Referring to the code excerpt:
printf("%s",&(sizeof 2[a])[a]);
First, most people don't realize it, but the [] operator it actually commutative. a[b] is equivalent to *(a + b), which is equivalent to *(b + a), which is equivalent to b[a].
So 2[a] is equivalent to a[2]. Since a has type const char [], the size of an element is the same as sizeof(char), which is 1.
So we now have:
printf("%s",&1[a]);
Well, 1[a] is equivalent to a[1], or *(a + 1). Applying the address-of operator gives &a[1], or a + 1 (note that &*x is just x).
So we have:
printf("%s", a + 1);
This just prints the string pointed to by a + 1, i.e. everything after the first character of a.
If you just reorder the [] operators without doing anything else, you can see that it's equivalent to:
printf("%s", &a[sizeof a[2]]);
If you break down each segment:
&(sizeof 2[a])[a]
2[a] = a[2]. a[2] = a char element at position 2
sizeof(char) = 1
(1)[a] = a[1]
&(a[1]) = a reference to the 'b' in "bcdefg"
printf() then prints the char array starting with b and ending at the null terminator

C language: find output of given program

So i have this main:
#define NUM 5
int main()
{
int a[NUM]={20,-90,450,-37,87};
int *p;
for (p=a; (char *)p < ((char *)a + sizeof(int) * NUM); ) //same meaning: for (p=a; p<a+NUM;)
*p++ = ++*p < 60 ? *p : 0; //same meaning: *(p++)=++(*p)<60?*p:0;
for(p=a; (char *)p < ((char *)a + sizeof(int) * NUM); )
printf("\n %d ", *p++);
return 0;
}
And i need to find what is the output.
So after try to understand without any idea i run it and this is the output:
21
-89
0
-36
0
So i will glad to explanation how to solve this kind of questions (i have exam soon and this type of questions probably i will see..)
EDIT:
at the beginning i want to understand what the first forstatement doing:
This jump 1 integer ? and what this going inside the block ?
And what is the different between *p++ and ++*p
The question is similar to Why are these constructs (using ++) undefined behavior in C? although not an exact duplicate due to the (subtle) sequence point inside the ?: operator.
There is no predictable output since the program contains undefined behavior.
While the sub-expression ++*p is sequenced in a well-defined way compared to *p because of the internal sequence point of the ?: operator, this is not true for the other combinations of sub-expressions. Most notably, the order of evaluation of the operands to = is not specified:
C11 6.5.15/3:
The evaluations of the operands are unsequenced.
*p++ is not sequenced in relation to ++*p. The order of evaluation of the sub-expressions is unspecified, and since there are multiple unsequenced side-effects on the same variable, the behavior is undefined.
Similarly, *p++ is not sequenced in relation to *p. This also leads to undefined behavior.
Summary: the code is broken and full of bugs. Anything can happen. Whoever gave you the assignment is incompetent.
at the beginning i want to understand what the first for statement doing
This is what one would call code obfuscation... The difficult part is obviously this one:
(char *)p < ((char *)a+sizeof(int)*NUM);
OK, we convert p to a pointer to char, then compare it to another pointer retrieved from array a that points to the first element past a: sizeof(int)*NUM is the size of the array - which we could have gotten much more easily by just having sizeof(a), so (char*)p < (char*)a + sizeof(a)
Be aware that comparing pointers other than with (in-)equality is undefined behaviour if the pointers do not point into the same array or one past the end of the latter (they do, in this example, though).
Typically, one would have this comparison as p < a + sizeof(a)/sizeof(*a) (or sizeof(a)/sizeof(a[0]), if you prefer).
*p++ increments the pointer and dereferences it afterwards, it is short for p = p + 1; *p = .... ++*p, on the other hand first dereferences the pointer and increments the value it is pointing to (note the difference to *++p, yet another variant - can you get it yourself?), i. e. it is equivalent to *p = *p + 1.
The entire line *p++ = ++*p<60 ? *p : 0; then shall do the following:
increment the value of *p
if the result is less than 60, use it, otherwise use 0
assign this to *p
increment p
However, this is undefined behaviour as there is no sequence point in between read and write access of p; you do not know if the left or the right side of the assignment is evaluated first, in the former case we would assign a[i] = ++a[i + 1], in the latter case, a[i] = ++a[i]! You might have gotten different output with another compiler!!!
However, these are only the two most likely outputs – actually, if falling into undefined behaviour, anything might happen, the compiler might just to ignore the piece of code in question, decide not to do anything at all (just exit from main right as the first instruction), the program might crash or it could even switch off the sun...
Be aware that one single location with undefined behaviour results in the whole program itself having undefined behaviour!
Short answer: because of this line
*p++ = ++*p<60 ? *p : 0;
it is impossible to say how the program behaves. When we access *p on the right-hand side, does it use the old or the new value of p, that is, before or after the p++ on the left-hand side gets to it? There is no rule in C to tell us. What there is instead is a rule that says that for this reason the code is undefined.
Unfortunately the person setting the question didn't understand this, thinks that "tricky" code line this is something to make a puzzle about, instead of something to be avoided at all costs.
The only way to really understand this kind of stuff (memory management, pointer behaviour, etc.) is to experiment yourself. Anyway, I smell someone is trying to seem clever fooling students, so I will try to clarify a few things.
int a[NUM]={20,-90,450,-37,87};
int *p;
This structure in memory would be something like:
This creates a vector of five int, so far, so good. The obvious move, given that data, is to run over the elements of a using p. You would do the following:
for(p = a; p < (a + NUM); ++p) {
printf("%d ", *p);
}
However, the first change to notice is that both loops convert the pointers to char. So, they would be:
for (p=a;(char *)p<((char *)a+sizeof(int)*NUM); ++p) {
printf("%d ", *p);
}
Instead of pointing to a with a pointer to int the code converts pto a pointer to char. Say your machine is a 32bit one. Then an int will probably occupy four bytes. With p being a pointer to int, when you do ++p then you effectively go to the next element in a, since transparently your compiler will jump four bytes. If you convert the int pointer to a char instead, then you cannot add NUM and assume that you are the end of the array anymore: a char is stored in one byte, so ((char *)p) + 5 will point to the second byte in the second element of a, provided it was pointing at the beginning of a before. That is way you have to call sizeof(int) and multiply it by NUM, in order to get the end of the array.
And finally, the infamous *p++ = ++*p<60 ? *p : 0;. This is something unfair to face students with, since as others have already pointed out, the behaviour of that code is undefined. Lets go expression by expression.
++*p means "access p and add 1 to the result. If p is pointing to the first position of a, then the result would be 21. ++*pnot only returns 21, but also stored 21 in memory in the place where you had 20. If you were only to return 21, you would write; *p + 1.
++*p<60 ? *p : 0 means "if the result of permanently adding 1 to the value pointed by p is less than 60, then return that result, otherwise return 0.
*p++ = x means "store the value of x in the memory address pointed by p, and then increment p. That's why you don't find ++p or p++ in the increment part of the for loop.
Now about the whole instruction (*p++ = ++*p<60 ? *p : 0;), it is undefined behaviour (check #Lundin's answer for more details). In summary, the most obvious problem is that you don't know which part (the left or the right one), around the assignment operator, is going to be evaluated first. You don't even know how the subexpressions in the expression at the right of the assignment operator are going to be evaluated (which order).
How could you fix this? It would be actually be very simple:
for (p=a;(char *)p<((char *)a+sizeof(int)*NUM); ++p) {
*p = (*p + 1) <60 ? (*p + 1) : 0;
}
And much more readable. Even better:
for (p = a; p < (a + NUM); ++p) {
*p = (*p + 1) <60 ? (*p + 1) : 0;
}
Hope this helps.

Arithmetic operations in IF loop

What does the below code do? I'm very confused with its working. Because I thought that the if loop runs till the range of int. But I'm confused when I try to print the value of i. Please help me out with this.
#include<stdio.h>
void main()
{
static int i;
for (;;)
if (i+++”Apple”)
printf(“Banana”);
else
break;
}
It is interpreted as i++ + "Apple". Since i is static and does not have an initializer, i++ yields 0. So the whole expression is 0 + some address or equivalent to if ("Apple").
EDIT
As Jonathan Leffler correctly notes in the comments, what I said above only applies to the first iteration. After that it will keep incrementing i and will keep printing "Banana".
I think at some point, due to overflows (if it doesn't crash) "Apple" + i will yield 0 and the loop will break. Again, I don't really know what a well-meaning compiler should do when one adds a pointer and a large number.
As Eric Postpischil commented, you can only advance the pointer until it points to one-past the allocated space. In your exxample adding 7 will advance the pointer one-past the allocated space ("Apples\0"). Adding more is undefined behavior and technically strange things can happen.
Use int main(void) instead of void main().
The expression i+++"Apple" is parsed as (i++) + "Apple"; the string literal "Apple" is converted from an expression of type "6-element array of char" to "pointer to char", and its value is the address of the first element of the array. The expression i++ evaluates to the current value of i, and as a side effect, the value in i is incremented by 1.
So, we're adding the result of the integer expression i++ to the pointer value resulting from the expression "Apple"; this gives us a new pointer value that's equal or greater than the address of "Apple". So assuming the address of the string literal "Apple" is 0x80123450, then basically we're evaluating the values
0x80123450 + 0
0x80123450 + 1
0x80123450 + 2
...
all of which should evaluate to non-zero, which causes the printf statement to be executed. The question is what happens when i++ results in an integer overflow (the behavior of which is not well defined) or the value of i+++"Apple" results in an overflow for a pointer value. It's not clear that i+++"Apple" will ever result in a 0-valued expression.
This code SHOULD Have been written like this:
char *apple = "Apple";
for(i = 0; apple[i++];)
printf("Banana");
Not only is it clearer than the code posted in the original, it is also clearer to see what it does. But I guess this came from "Look how bizarre we can write things in C". There are lots of things that are possible in C that isn't a great idea.
It is also possible to learn to balance a plate of hot food on your head for the purpose of serving yourself dinner. It doesn't make it a particularly great idea - unless you don't have hands and feet, I suppose... ;)
Edit: Except this is wrong... The equivalent is:
char *apple = "Apple";
for(i = 0; apple+i++ != NULL;)
printf("Banana");
On a 64-bit machine, that will take a while. If it finishes in reasonable time (sending output to /dev/null), I will update. It takes approximitely three minutes on my machine (AMD 3.4GHz Phenom II).

Weird C Syntax 1["ABCDE"]?

Can anyone please help me understand the following code:
int d = 4;
printf(&d["Hay!Hello %c\n"], &4["BuddyWorld"]); // Hello (some address in char)
printf(&d["Hay!Hello %c\n"], 4["BuddyWorld"]); // Hello y
printf(&d["Hay!Hello %s\n"], 4["BuddyWorld"]); // Segmentation fault
printf(&d["Hay!Hello %s\n"], &4["BuddyWorld"]); // Hello yWorld
printf("d[Hay!Hello %s\n"], &4["BuddyWorld"]);
/* warning: passing argument 1 of 'printf' makes pointer
from integer without a cast */
What is exactly the d[] or &d[] operator? (d is an integer)
Why does &4["BuddyWorld"] and 4[BuddyWorld] yields to different values? ('W' and 'y' respectively)
When you write something like a[i], it gets expanded into *(a + i). (We say a[i] is syntactic sugar for *(a + i)).
Addition is commutative, so "BuddyWorld"[4] = *("BuddyWorld" + 4) = *(4 + "BuddyWorld") = 4["BuddyWorld"], where "BuddyWorld" implicitly stands for its address in memory.
Subscripting in C is weird. a[b] is turned into *(a + b) (the thing at the address obtained by adding b to the pointer a). However, since a + b == b + a, it works the other way around as well (a[b] == b[a]). That's all that's going on. In particular, "HelloWorld" is really a pointer to a character array that stores the characters of the string.
d["Hay!Hello %c\n"] is the same as "Hay!Hello %c\n"[d].
And the & operator gives the address of the pointed content

Resources