I did a recursion exercise and I could not understand what is the difference between doing *p++ or *p+=1.
Both of them should add 1 to the value pointed at but for some reason *p+=1 works and *p++ doesn't.
void rec(char a[], int *p ,int i)
{
if(a[i+1]== '\0')
return;
if(a[i]==a[i+1])
*p+=1;
rec(a, p, i+1);
}
void rec(char a[], int *p ,int i)
{
if(a[i+1]== '\0')
return;
if(a[i]==a[i+1])
*p++;
rec(a, p, i+1);
}
*p += 1; means, dereference the pointer p and then increment the dereferenced value by 1. While *p++; means
*p;
p += 1; // Increment the pointer itself
This is because ++ has higher precedence than * operator so compiler will parse it as *(p++);.
(*p)++ is equivalent to *p += 1;.
Precedence wise
++ > * > +=
Here *p+=1 is increasing the value that is pointed by p. Here the value at the memory location pointed by p is incremented. You can see the change in your code.
In the second case, *p++ it is just increasing the pointer p and then it de-references the value but you don't assign that r-value anywhere. This is not changing the actual content that there is in the memory pointed by p.
That is why in second case you don't see any change in the working variables and concluded that it doesn't work which is certainly not the case.
Related
I stumbled into this while solving an exercise:
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
if (!s || !f)
return ;
i = 0;
while (s[i++])
f(i, s + i);
}
Why doesn't the post increment in the while work while if i do this:
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
if (!s || !f)
return ;
i = -1;
while (s[++i])
f(i, s + i);
}
It works?
I'm new and still very confused to the whole pointer concept is there any nuance here that I don't know about?
The problem is the match between the comparison and the function call.
Consider the first iteration. In the first snippet it would be:
if(!s[0]) break;
f(1, s + 1);
In the second snippet it would be:
if(!s[0]) break;
f(0, s + 0);
The increment operators in C specify that, in addition to a value being computed by the expression, a side-effect occurs.
You might think that this is somehow special or peculiar to these operators, but in fact it isn't. The assignment operators are also this way.
For instance, ++(EXPR) is equivalent to (EXPR) = (EXPR) + 1, except that EXPR is only evaluated once.
Both of these expressions calculate the result (EXPR) + 1, and also have the side effect of storing that value back into (EXPR).
The side effect happens any time during the evaluation of the full expression which contains this subexpression.
Given:
while (s[i++])
f(i, s + i);
We have two full expressions here: the controlling expression of the while loop, s[i++], is a full expression, and so is the f(i, s + i) function call.
The side effects required by each full expression are settled before the next full expression is evaluated. The previous full expression sees the prior value, and the subsequent full expression sees the new value.
In other words, i++ here means:
Calculate the value of i and also put i + 1 into i.
Make sure that this i update is done sometime during the evaluation of the full expression s[i++].
Therefore, the expression f(i, s + i) is going to observe the new value of i, not the previous value of i that was used to calculate s[i]. The function call will not be given the character that was tested to be non-zero, but the next character after it.
The important fact here is that side-effects are sequenced at the level of individual full expressions, not statements. Here, i++ does not mean "increment i after each iteration of the entire while loop, while i keeps referring to the old value". If it worked that way, the code would work; but it doesn't.
Thus your revised statement fixed the consistency:
while (s[++i])
f(i, s + i);
because here ++i means:
Calculate the value of i + 1 and also put that value into i.
Same (2) as above.
Here, the controlling expression of while tests s[i] where i is the new, incremented value of i; and the function call f(i, s + i) refers to the same i. The controlling expression and function call are consistent: they work with the same character of the string.
You had to compensate for the preincrement by initializing i to -1.
If you want to increment a variable after each iteration of the loop, and to do that near the top of the loop, then the for construct is designed for exactly that:
// misconception: // similar idea, correct:
i = 0;
while (s[i++]) for (i = 0; s[i]; i++)
f(i, s + i); f(i, s + i);
The for loop lets us have a kind of "postincrement" at the level of an entire statement: it has a place in the head syntax where we can specify the increment expressions that will evaluate after the entire body.
By the way, since i is unsigned int (which can also be specified as unsigned, without int), that type does not actually have a -1 value in its range. When we do this:
unsigned int x = -1; // initialize or assign a -1 value to unsigned
the negative value gets reduced to the smallest positive residue modulo UINT_MAX + 1, and the resulting value is what is actually assigned.
The value -1 goes to UINT_MAX. So you are really doing this:
i = UINT_MAX; // same meaning as i = -1.
this works because if i is unsigned and contains the maximum value UINT_MAX, when we then increment i, it goes to zero. This modulo or "wrapping" arithmetic is part of the definition of the unsigned type; it is specified in the language standard. In the other direction, decrementing a zero-valued unsigned likewise produces UINT_MAX.
Also, as a matter of style, when referencing arrays, do not mix the ptr + index and ptr[index] notations. This is better:
// while the character isn't null, pass a pointer to that
// same character to f:
while (s[++i])
f(i, &s[i]); // address of the character
This &s[i] means &*(s + i) where the &* ("address of dereferenced pointer") operator combination "algebraically cancels out" leaving s + i; it is no less efficient.
This recommendation is particularly relevant if the function f is working with that one character s[i] and not the entire s + i substring of s. The &array[index] notation tends to be used (as a rule of thumb) when the emphasis is on a particular array element.
As a reader of C, you cannot trust that, of course: &array[index] in someone else's program could be used to calculate a value which a function then uses to access other elements of the array, not only that one. As a writer of C, though, you can make your code "look like what it is doing", so there are fewer pitfalls for someone else.
If you do simple debugging you will see what the problem is.
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
i = 0;
while (s[i++])
{
printf("i = %d\n", i);
if(f) f(i, s + i);
}
}
void ft_striteri1(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
i = -1;
while (s[++i])
{
printf("i = %d\n", i);
if(f) f(i, s + i);
}
}
int main()
{
ft_striteri("Hello", NULL);
printf("\n");
ft_striteri1("Hello", NULL);
}
https://godbolt.org/z/cqb1aMGje
Result:
i = 1
i = 2
i = 3
i = 4
i = 5
i = 0
i = 1
i = 2
i = 3
i = 4
Function with postincrement iterates from index 1 to 5 instead of 0 to 4.
But your both functions do not use the correct type for the indexes. It should be size_t instead of int.
I would personally write another way, having "positive" test checking if parameters are OK and have only one return point:
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
size_t i = 0;
if(s && f)
{
while (s[i])
{
f(i, s + i);
i++; // or ++i; - it makes no difference
}
}
}
I don't know about nuance, but here is an equivalent to your first:
void first(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
if (!s || !f)
return ;
i = 0;
while (s[i]) {
f(i, s + i + 1);
s = s + 1;
}
}
and second:
void second(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
if (!s || !f)
return ;
i = -1;
while (s[i+1]) {
f(i, s + i + 1);
i = i + 1;
}
}
Really, neither look right to me; I would think you would want:
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
unsigned int i;
if (!s || !f)
return ;
i = 0
while (s[i]) {
f(i, s + i);
i++
}
}
which, in idiomatic style might be:
void ft_striteri(char *s, void (*f)(unsigned int, char*))
{
int c;
if (!s || !f)
return ;
for (; *s; s++)
f(i, s);
}
In this code snippet, strncpy has the n value as a difference of two char pointers. How can two string pointers be subtracted? What is the value of n here?
The program does compile successfully but doesn't the size have to be an int value?
void replace(char *s1) {
char r[4][5] = { "get", "tell", "your", "house" };
char rep[4][10] = { "see", "us", "tall", "kite" };
char buff[500];
int i;
char *ch;
for (i < 0; i < 4; i++) {
if ((ch = strstr(s1, r[i]))) {
strncpy(buff, s1, ch - s1);
buff[ch-s1] = 0;
sprintf(buff + (ch - s1), "%s%s", rep[i], ch + strlen(r[i]));
s1[0] = 0;
strcpy(s1, buff);
return replace(s1);
}
}
}
If you have two pointers p and q that point into the same array, then p - q evaluates to the (signed) number of elements between p and q in the array. For example, consider this code:
int array[137];
int* p = &arr[10];
int* q = &arr[5];
ptrdiff_t diff = p - q;
Here, p points to the tenth element of the array, q points to the fifth element of the array, so p - q would be five. (The special type ptrdiff_t is an integer type that’s big enough to hold the difference of any two pointers.)
Another way to interpret this difference is to ask “what index does pointer p point to if we imagine the array starts where q is pointing?” In that case, the answer is five, since if we treat q as the base of the array, then p would be at index five. In your case, your pointer ch was set equal to the return value of strstr, so it points somewhere into the middle of s1. The expression ch - s1 then means “the position in the string where ch points.”
Making an analogy to points in space: if you have two points p and q, you can think of p - q as a vector representing the direction you need to go to get from q to p. You can’t meaningfully add the points p and q to get p + q, though, just as you can’t add two pointers in C.
++*P--;
That is a question from an exam, if P a pointer to any element in an array, explain what this statement really does.
I even wrote a simple code to evaluate it:
int i;
int* array = calloc(10, sizeof(int));
for (i = 0; i < 10; i++) {
array[i] = i;
printf("%d,", array[i]);
}
int* P = array + 5;
printf("\n %p", P);
printf("\n %d", *P);
++*P--;
printf("\n %p", P);
printf("\n %d \n", *P);
for (i = 0; i < 10; i++) {
printf("%d,", array[i]);
}
But the output confuses me even more:
0,1,2,3,4,5,6,7,8,9,
0x100105534
5
0x100105530
4
0,1,2,3,4,6,6,7,8,9,
It looks like it first dereferences P, then increases its value and then decreases value of pointer P, but why?
According to K&R table 2-1 from p53 (see the picture below)
++, --, and * (dereference) has the same precedence and associativity from right to left.
So first step should be decreasing value of P, then dereference and then increasing dereferenced value, am I wrong?
You are correct that the precedence is
++(*(P--))
But note that the decrement is a postfix operation: even though the change to P happens first, the rest of the expression uses the old value of P. So in your example, first P is decremented to array+4, but the value of P-- is array+5, so array[5] gets incremented.
You can imagine this expression
++*P--
the following way
int *tmp = p;
--p;
int value = *tmp;
++value;
Here is a demonstrative program
#include <stdio.h>
int main( void )
{
char s[] = "Hello World";
char *p = s + 6;
std::printf( "%c\n", ++*p-- );
std::printf( "%s\n", s );
p = s + 6;
char *tmp = p--;
char value = *tmp;
++value;
std::printf( "%c\n", value );
std::printf( "%s\n", s );
}
The program output is
X
Hello Xorld
Y
Hello Xorld
The difference in the outputting the string is that expression ++*p-- changes the string itself but expression ++value; changes a separate object. But the logic is similar.
Postfix expression p-- has the highest priority but its value is the value of p before decreasing.
Unary operators ++ and * in expression ++*p-- group right to left. So at first operator * is applied to the expression and after that operator ++ is applied.
Why is
int i;
int *p = &i;
right, while
int i, *p;
*p = &i;
is wrong?
Is there any difference between * operator used in declaration (int *p = &i) and expression (*p = &i)?
In your second code block, this:
int i, *p;
*p = &i;
can be fixed to:
int i, *p;
p = &i;
p is still declared as a pointer to an int, but you want to store the address of i to p.
In your code, *p = &i stores the address of i to some area in memory that p points to (since you didn't initialize it).
Yes there is difference - in the first form * is part of the type definition int *.
In the second form its an unary dereference operator. Also there is an error with the second expression - when you are assigning to a pointer, there is no need to dereference it.
(*p) evaluates to type int while p evaluates to type int *; &i evaluates to type int *. Hence assinging the address of int variable i to pointer p should read p=&i;
as in the title, what's the difference because these two seem to get me the same results?
No they are not the same. Assume that d is a pointer to int:
int n = 0;
int* d = &n;
*d++; // d++ then *d, but d++ is applied after the statement.
(*d)++; // == n++, just add one to the place where d points to.
I think there is an example in K&R where we need to copy a c-string to another:
char* first = "hello world!";
char* second = malloc(strlen(first)+1);
....
while(*second++ = *first++)
{
// nothing goes here :)
}
The code is simple, put the character pointed by first into the character pointed by second, then increment both pointers after the expression. Of course when the last character is copied which is '\0', the expression results to false and it stops!
The increment ++ has higher operator precedence than the dereference *, so *d++ increments the pointer d to point to the next location within the array, but the result of ++ is the original pointer d, so *d returns the original element being pointed to. Conversely, (*d)++ just increments the value being pointed to.
Example:
// Case 1
int array[2] = {1, 2};
int *d = &array[0];
int x = *d++;
assert(x == 1 && d == &array[1]); // x gets the first element, d points to the second
// Case 2
int array[2] = {1, 2};
int *d = &array[0];
int x = (*d)++;
assert(x == 1 && d == &array[0] && array[0] == 2);
// array[0] gets incremented, d still points there, but x receives old value
In the official C terminology, these expressions do give you the same results, as they should. In the proper terminology, the "result" of a non-void expression is what that expression evaluates to. Both of your expressions evaluate to the initial value of *d, so not surprisingly, the results are the same.
However, an addition to a "result" every expression in C has zero or more so called "side effects". And side effects of these two expressions are completely different. The first expression increments the value of pointer 'd'. The second expression increments the value of '*d' (the pointed value).
The first increments the pointer, the second increments the value pointed to.
As an experiment, try this:
int main() {
int x = 20;
int *d = &x;
printf("d = %p\n", d);
int z = (*d)++;
printf("z = %d\n", z);
printf("d = %p\n", d);
int y = *d++;
printf("y = %d\n", y);
printf("d = %p\n", d);
}
They do return the same result, but the state change in your program is completely different.
This is easiest to understand if we just expand out the operations.
x = *d++;
// same as
x = *d;
d += 1; // remember that pointers increment by the size of the thing they point to
x = (*d)++;
// same as
x = *d;
*d += 1; // unless *d is also a pointer, this will likely really just add 1
I don't have a compiler handy.
a = (*d)++;
b = (*d);
is a==b? i don't think it is.