What does "20"[1] do? - c

In a test exam, we were told to find the value of some expressions.
All but 1 were clear, which was "20"[1]. I thought it was the 1st index of the number, so 0, but testing with a computer it prints 48.
What exactly does that 'function' do?

It's not a function, it's just indexing an array.
"20" here is a character array, and we're taking the value at index 1 - which is '0' - the character '0'.
This is the same as
char chArr[] = "20"; // using a variable to hold the array
printf ("%d", chArr[1]); // use indexing on the variable, decimal value 48
printf ("%c", chArr[1]); // same as above, will print character representation, 0
The decimal value of '0' is 48, according to ASCII encoding, the most common encoding around these days.

Well, depending on your point of view it's either '0', 48, or 0x30.
#include <stdio.h>
int main()
{
printf("'%c' %d 0x%X\n", "20"[1], "20"[1], "20"[1]);
return 0;
}
The above prints
'0' 48 0x30

In this subscripting expression
"20"[1]
"20" is a string literal that has the type char[3]. Used in expressions the literal is converted to pointer to its first element.
So this expression
"20"[1]
yields the second element of the string literal that is '0'.
You can imagine this record like
char *p = "20";
char c = p[1];
48 is the ASCII value of the character '0'.
A more exotic record can look like
1["20"]
that is equivalent to the previous record.
From the C Standard (6.5.2.1 Array subscripting)
2 A postfix expression followed by an expression in square brackets []
is a subscripted designation of an element of an array object. The
definition of the subscript operator [] is that E1[E2] is identical to
(*((E1)+(E2))). Because of the conversion rules that apply to the
binary + operator, if E1 is an array object (equivalently, a pointer
to the initial element of an array object) and E2 is an integer,
E1[E2] designates the E2-th element of E1 (counting from zero).
Here is a demonstrative program
#include <stdio.h>
int main(void)
{
printf( "\"20\"[1] == '%c' and its ASCII value is %d\n", "20"[1], "20"[1] );
printf( "1[\"20\"] == '%c' and its ASCII value is %d\n", 1["20"], 1["20"] );
return 0;
}
Its output is
"20"[1] == '0' and its ASCII value is 48
1["20"] == '0' and its ASCII value is 48

Related

Is *(arr -1) the same as arr[-1]?

I'm trying to solve this question that has a vector and there is a pointer that leads to an negative index. I'd like to know if C ignores it and considers it as a positive number or it goes backwards in the vector, like -1 being the last element of the array.
Yes, you can have negative indexes. This follows from the definition of pointer arithmetic in C, namely that p[i] is exactly equivalent to *(p + i), and it's perfectly legal for i to be a negative number.
So, no, the sign is not ignored. Also, if you're dealing directly with an array, there's no rule that says that a negative index is computed with respect to the end of the array. If you're dealing directly with an array, a negative index ends up trying to access memory "off to the left" of the beginning of the array, and is quite against the rules, leading to undefined behavior.
You might wish to try this illustrative program:
#include <stdio.h>
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int *p = &arr[4];
int *endp = &arr[8];
printf("%d %d %d\n", arr[0], arr[4], arr[8]); /* prints "1 5 9" */
printf("%d %d %d\n", p[-1], p[0], p[1]); /* prints "4 5 6" */
printf("%d %d %d\n", endp[-2], endp[-1], endp[0]); /* prints "7 8 9" */
printf("x %d %d x\n", arr[-1], endp[1]); /* WRONG, undefined */
}
The last line is, as the comment indicates, wrong. It attempts to access memory outside of the array arr. It will print "random" garbage values, or theoretically it might crash.
Is *(arr -1) the same as arr[-1]?
Yes. Strictly speaking, the array subscripting [] operator is defined as arr[n] being equivalent to *( (arr) + (n) ). In this case: *( (arr) + (-1) ).
or it goes backwards in the vector
Well it goes backwards until it reaches array item 0, from there on you access the array out of bounds. It doesn't "wrap around" the index or anything like that. Example:
int arr[3] = ...;
int* ptr=arr+1;
printf("%d\n", ptr[-1]); // ok, prints item 0
int* ptr=arr;
printf("%d\n", ptr[-1]); // not ok, access out-of-bounds.
According to the C Standard (6.5.2.1 Array subscripting)
2 A postfix expression followed by an expression in square brackets []
is a subscripted designation of an element of an array object. The
definition of the subscript operator [] is that E1[E2] is identical to
(*((E1)+(E2))). Because of the conversion rules that apply to the
binary + operator, if E1 is an array object (equivalently, a pointer
to the initial element of an array object) and E2 is an integer,
E1[E2] designates the E2-th element of E1 (counting from zero).
So the expression arr[-1] is evaluated as *( arr + -1 ) that is the same as *( arr - 1).
However pay attention to that arr[-1] is not the same as -1[arr] because before the square brackets there must be a postfix expression
postfix-expression [ expression ]
and the unary minus operator has less precedence than a protfix expression.
But you may write ( -1 )[arr] that is the same as arr[-1].

sizeof operator in C behavior with strings [duplicate]

This question already has answers here:
Behaviour of sizeof with string
(2 answers)
Closed 2 years ago.
For the sizeof operator I am seeing following results; and I am not able understand the reason behind the same.
What I understand is sizeof operator returns the result in terms of size_t
Below are the results,
sizeof("6") -> 2
sizeof("a") -> 2
sizeof('a') -> 4
sizeof("something") -> 10
sizeof("some") -> 5
By definition (C11 3.6), 1 char requires 1 byte (may not be 1 octet in some exotic system)
"6" has type char[2], so 2 bytes
"a" has type char[2]
'a' has type int ==> in your system, int requires 4 bytes
"something" has type char[10]
"some" has type char[5]
Note that "a" and 'a' are very different things: "a" is an array of char with 2 elements; 'a' is an int value, very much like 42 or -1.
In records like this
sizeof("6") -> 2
there is used a string literal as an operand.
String literals are character arrays that store a sequence of characters terminated with the zero character '\0'.
So for example the string literal "6" is stored in memory like
char literal_6[] = { '6', '\0' };
Or this declaration is equivalent to
char literal_6[2] = { '6', '\0' };
Note: for example the string literal "some" is stored in memory like a character array declared as
char literal_some[] = { 's', 'o', 'm', 'e', '\0' };
So the expression sizeof("6") is equivalent to the expression sizeof( char[2] ).
In this record
sizeof('a') -> 4
there is used integer character constant '4' that has the type int.
So this expression sizeof('a') is equivalent to the expression sizeof( int ).
It is interesting to note that for example sizeof("something") is not equal to sizeof("something" + 0). In the last expression the character array that denotes the string literal is implicitly converted to pointer to its first element. So the last expression is equivalent to the expression sizeof( char * ).
Also pay attention to that if you have for example
int x = 10;
size_t n = sizeof( ++x );
then x will not be equal to 11 after the declaration of n because in this case the expression used as an operand of the sizeof operator is not evaluated. It is only the type of the expression that is important.
On the other hand if you have a variable length array then the operator sizeof will evaluate at run-time to determine its size. Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
for ( int i = 1; i < 5; i++ )
{
int a[i];
printf( "sizeof( a[%d] ) = %zu\n", i, sizeof( a ) );
}
return 0;
}
The program output is
sizeof( a[1] ) = 4
sizeof( a[2] ) = 8
sizeof( a[3] ) = 12
sizeof( a[4] ) = 16

string manipulation with %s format

May you explain the following output:
main()
{
char f[] = "qwertyuiopasd";
printf("%s\n", f + f[6] - f[8]);
printf("%s", f + f[4] - f[8]);
}
output:
uiopasd
yuiopasd
For example regarding the first printf:
f[8] should represent the char 'o'
f[6] should represent the char 'u'
%s format prints the string (printf("%s", f) is giving the whole "qwertyuiopasd")
So how does it come together, what is the byte manipulation here?
There are multiple problems in the code posted:
the missing return type for main is an obsolete syntax. you should use int main().
the prototype for printf is not in scope when the calls are compiled. This has undefined behavior. You should include <stdio.h>.
the expression f + f[6] - f[8] has undefined behavior: addition is left associative, so f + f[6] - f[8] is evaluated as (f + f[6]) - f[8]. f[6], which is the letter u is unlikely to have a value less than 14 (in ASCII, its value is 117) so f + f[6] points well beyond the end of the string, thus is an invalid pointer and computing f + f[6] - f[8] has undefined behavior, in spite of the fact that 'u' - 'o' has the value 6 for the ASCII character set. The expression should be changed to f + (f[6] - f[8]).
Assuming ASCII, the letters o, u and t have values 111, 117 and 116.
f + (f[6] - f[8]) is f + ('u' - 'o') which is f + (117 - 111) or f + 6.
f + 6 is the address of f[6], hence a pointer to the 7th character of the string "qwertyuiopasd". Printing this string produces uiopasd.
Assume the characters follows the ASCII scheme, the ASCII value of the following characters are :
o (f[8]): 111
u (f[6]): 117
t (f[4]): 116
f is the pointer to the char[], the first statement values to f + 6, this pointer will point to the 6th element of the array, and on printing, it will print from the sixth element till the point it encounters \0.
Similarly, the second statement evaluates to f + 5, thus you get yuiopasd as output.
What does f + n means?
You can perform the following arithmetic on the pointers ++, --, +, -. The pointer stores the memory address, and the increment operator on a pointer will increase the address value by the size of the type.
for eg for an integer, if f points to address location 1000, and we are storing 4 bytes int in the array, then f + 1 will point to 1004, which is the next element in the array.
it is a simple pointer arithmetic which will be easier to understand with this example
int main(void)
{
char f[] = "9876543210";
printf("%s , f[6]=%d, f[8]=%d, f[6]-f[8]=%d, f + f[6] - f[8] = %s\n",f, f[6], f[8], f[6]-f[8], f + f[6] - f[8]);
The result is :
9876543210 , f[6]=51, f[8]=49, f[6]-f[8]=2, f + f[6] - f[8] = 76543210
f[n] is the integer value of the nth index element of the array.
In this example the difference between ASCII codes of the 6th and 8th elements is 2.
When we add 2 to the char pointer it will reference the element 2 chars ahead which in our case is '7'
This is all about pointer arithmetic. The expression f + f[6] - f[8] evaluates to a char* pointer (like its first operand, because the name of an array variable is syntactically equivalent to a pointer to its first element), and will expand to this:
f + (int)'u' - (int)'o'
(where 'u' and 'o' represent f[6] and f[8], respectively).
The values that represent the characters, 'u' and 'o', are (on almost all modern systems, which use the ASCII system), separated by 6, so the expression adds 6 to the f address and prints the string starting from its 7th element.
Similarly for the expression f + f[4] - f[8] - but here, the difference is only 5 ('t' - 'o').

Achieve the output in one statement

I was given this question by my school teacher. I was supposed to add in one statement in the C code and achieve this desired output.
I have tried but i am stuck. I think the main idea of this question is to establish the relationship between the int x[] and the y[] string as i increases from 0 to 6.
The code is below:
#include <stdio.h>
int main(){
int i, x[] = {-5,10,-10,-2,23,-20};
char y[20] = "goodbye";
char * p = y;
for (i=0;i<6;i++){
*(p + i) = //Fill in the one line statement here
}
y[6] = '\0';
printf("%s\n",p); //should print out "byebye"
}
As you can see the ascii value of the characters b is from 5 lesser than g and similarly for y it is 10 greater than o..so it will be (This meets the criteria of using x) (solution utilizing the values of x)
*(p+i) = (char)(*(p+i)+x[i]);
Yes one thing that is mentioned by rici is very important. *(p+i) is nothing other than p[i] - in fact it is much leaner to use and underneath it is still being calculated as *(p+i).
From standard 6.5.2.1p2 C11 N1570
A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).
The standard mentions this also. Being said this it would be as simple as
p[i]+=x[i];
Thoughts that came to my mind while solving.
It would be (things that came to my mind when I saw it very first time - this is establishing no relation between x and y).
*(p + i) = "byebye"[i];
String literals are basically arrays and it decays into pointer to the first element of it and then we do this *(decayed pointer + i). This will eventually assign the characters of "byebye" to the char array y.
Or something like this:- (too many hardcoded values - this does relate x and y)
*(p+i) = *(y+4+i%3);
Using a the modulus operation you can manipulate your loop to assign byebye to the 6 *char values in p.
This works because you are starting from y[4] which is 'b'.
The 6 in the for loop is your next hint. You need to iterate through bye twice. bye has 3 characters.
This gives you:
*(p + i) = y[4+(i%3)];

Unusual behavior of ternary operator?

i was just playing around with the ternary operator in my c class today. And found this odd behavior.
#include <stdio.h>
#include <stdbool.h>
main()
{
int x='0' ? 1 : 2;
printf("%i",x);
}
returns 1 as expected.But
#include <stdio.h>
#include <stdbool.h>
main()
{
int x='0'==true ? 1 : 2;
printf("%i",x);
}
returns 2 while i expect it to return 1.
The value of '0' is not zero, it is whatever integer value encodes the digit '0' on your system. Typically 48 (in encodings borring from ASCII), which is then not equal to true when interpreted as an integer, which is 1.
So the first of your code lines is equivalent to
int x = (48 != 0) ? 1 : 2;
which clearly evaluates to 1. The second is
int x = (48 == 1) ? 1 : 2;
which just as clearly evaluates to 2.
Maybe you are confusing '\0' and '0'
The value of the character constant
'\0'
is always 0 in C.
The value of the character constant
'0'
is implementation defined and depends on the character set. For ASCII, it is 0x30.
Also note that the macro true is defined to the value 1 and not 0.
That's because (assuming ASCII) '0' represents the integer 0x30, i.e. 48, and true represents the integer 1. So they're not equal.
In C, any nonzero value is considered true, but true itself is 1, and 1 is what you get from any built-in Boolean test (for example, 0 == 0 is 1).
true is defined as 1. '0' in ASCII is 0x30 which is not equal to 1.
Therefore the condition '0'==true is not true.
That's because '0' != true. The boolean value gets promoted to an integer type and is equal to 1 whereas '0' is equal to 48
'0' does not equal true, so the result of '0'==true is 0 (false). This is assigned to x and passed to the ternary operator, giving the result you see.
If you intended something else, you should use brackets to clarify the order of precedence you want, or break your code up into multiple statements.

Resources