why pre increment works with pointer but not post increment - c

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);
}

Related

Regarding question about function pointer in C?

I was reading about function pointer. That it contains address of instructions. And there I encountered one question to find an element in array using function pointer. Here is the code.
#include <stdio.h>
#include <stdbool.h>
bool compare(const void* a, const void* b)
{
return (*(int*)a == *(int*)b);
}
int search(void* arr, int arr_size, int ele_size, void* x, bool compare(const void*, const void*))
{
char* ptr = (char*)arr; // Here why not int *ptr = (int*)arr;
int i;
for (i = 0; i < arr_size; i++)
{
if (compare(ptr + i * ele_size, x))
{
return i;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 5, 7, 90, 70 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 7;
printf("Returned index is %d ", search(arr, n, sizeof(int), &x, compare));
return 0;
}
In the search function char *ptr = (char*)arr; is used which is giving perfect answer = 2.
But when I have used int *ptr = (int*)arr; it gives -1 as answer.
Why is this? Can anyone explain this?
A char is the smallest addressable unit in any C program, and on most system it corresponds to a single byte. That treats the array as a generic sequence of bytes, and uses the ele_size to calculate the byte-position of each element with ptr + i*ele_size.
If you use int *ptr then the byte-position calculation will be wrong by a factor of sizeof(int) (typically 4), since the pointer arithmetic will be done in units of the base type (int instead of char).
The function search knows nothing about what is the type of elements of the array pointed to by the pointer arr of the type void *.
So casting the pointer to the type int * does not make a sense. If to do so then the expression ptr + i*ele_size where the pointer arithmetic is used will produce an incorrect result.
That it contains address of instructions
There is a subtle difference between normal (object) pointers and function pointers. It is not possible to access the single instructions of a function - they do not have the same length.
With other pointers the increment (arithmetic) is adapted to the type, whether as p[i] or p + i or *(p+i).
Side note: there still is int at the bottom of the call chain:
return (*(int*)a == *(int*)b);

Ex. 2.1 K&R 2nd edition: How can I calculate the variables?

I am a beginner in programming. I referred to power function in chapter 1 and modified it to be power_sum function. My calculation is to insert value of bits in "show_val()" to show range of each variable. The problem is in the main when I want to insert a value into show_val. Please guide me how to solve this. Thank you.
#include <stdio.h>
int power_sum(int base, int n);
void show_val(int power);
int main() {
unsigned char vc = show_val(8);
/* I try to show range of unsigned char here, but because show_val
is a void function, so it becomes error.*/
}
/* power_sum: raise base to n-th power and sum up; n => 0 */
int power_sum(int base, int n) {
int i, p, sum;
p = 1;
sum = 0;
for (i = 1; i <= n; ++i) {
p = p * base;
sum = sum + p;
}
sum = sum - 2;
return sum;
}
/* show_val: to show value of each variable */
void show_val(int pw) {
int n;
int i;
n = power_sum(2, pw);
for (i = 0; i < 10; ++i) /* to display increments of a value ten times */ {
printf("%d\n", ++n);
}
}
You are trying to assign void function void show_val(int pw) (a function that returns nothing) to unsigned char vc variable. If you want to return value from show_val function change: int show_val(int pw) and return something.
Otherwise, if you don't want to return anything, you can just call function in main:
int main()
{
show_val(8);
}
unsigned char vc = show_val(8);
Let us break the above piece of code into LHS and RHS.
LHS :
Its a variable expecting a character to be inputed.
Now what is being done in RHS
RHS:
You have given show_val(8)
Which is a mistake
Why?
Because if you see you show_val declaration:
void show_val(int)
You are returning a void i.e nothing.
And trying to equate with char on LHS.
So, the compiler will definitely throw an error.
There are more changes to be made,
1st edit this part correctly in the question if you are clear and then we can look upon the other changes.

Implement F# List.scan in C?

How would you implement a function with the same behavior as List.scan in F#?
Here is the description:
Applies a function to each element of the collection, threading an
accumulator argument through the computation. This function takes the
second argument, and applies the function to it and the first element
of the list. Then, it passes this result into the function along with
the second element, and so on. Finally, it returns the list of
intermediate results and the final result. (link)
Of course I have attempted myself and here is my pseudocode (I do not expect you to provide working c-code btw): For the call scan(myop, ne, x), I have the pseudocode
int n = length(x);
char *b = (char*)malloc(n); //Allocate n bytes
b[0] = ne;
int i = 0;
while (i < n) {
bool tmp = myop(b[i-1], x[i]);
bool b[i] = tmp;
i = i+1;
}
bool list y = b;
but this fails for i > 0 since then b[i] is not initialized. How would you implement this?
but this fails for i > 0 since then b[i] is not initialized
In your pseudo code:
bool tmp = myop(b[i-1], x[i]);
It will be failed when i = 0 (it means at the first time you enter the while loop), because you try to access the index -1 (i = 0, so b[i-1] becomes b[-1]) of b, it is undefined behavior.
You have to begin the while loop at i = 1 at least. So, before the loop:
b[0] = ne;
int i = 0;
Can change to:
b[0] = ne;
// do something with b[0] if you want.
int i = 1;
In your code, you refer to the previous element even for i == 0, which is incorrect. You could special case the first element by storing b[0] = myop(ne, x[0]) and start the loop at i = 1, but this solution would not work for an empty source list (n == 0). Furthermore, length(x) cannot be computed from a pointer, only from an actual array as sizeof(x) / sizeof(*x). It is best to pass the size as a separate argument.
Here is a C function that performs the semantics of List.scan for int arguments, taking a pointer to the function, an initial value, an array of int values, the length of this array and a pointer to the destination array, which can be the same as the source array:
int array_scan(int (*func)(int, int), int v1, const int *src, size_t count, int *dest) {
for (size_t i = 0; i < count; i++) {
int v2 = src[i];
dest[i] = v1;
v1 = func(v1, v2);
}
return v0;
}
In C there is no way to define lambda expressions inline, so you must define the function separately with a name and pass it explicitly to array_scan.

In which precedence is this statement evaluated?

++*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.

C For Loop Not Working?

I'm working with strings in C as character arrays, and I'm trying to ensure that I can dynamically pass values into my for loops.
The following code works, no problem:
for (int i = -6; i < 11; i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}
In fact, this code works, too:
for (int i = -strlen(fragments[2]) + 1; i < 11; i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}
But for some reason, this code doesn't print ANYTHING:
for (int i = -strlen(fragments[2]) + 1; i < strlen(fragments[1]); i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}
I have checked the values for both -strlen(fragments[2]) + 1 and strlen(fragments[1]) just before the loop and they check out to -6 and 11 respectively. Clearly the loop works when I place those values directly into their places, but when I replace the second one with the strlen calculations, it breaks and I can't figure out why for the life of me. Help?
Edit
OverlapStrength takes its arguments as constants so I can't change them, so I'm pretty sure I'm not changing the fragments as I go. Here's the method declaration:
int OverlapStrength(const char one[], const char two[], int startOne, int startTwo)
The contents of the fragments shouldn't be important, but they're simply strings that I'm trying to piece back together from overlapping fragments. I have already checked that my fragments are all coming out properly and that their lengths are computed properly when done outside of declaring this loop.
strlen returns value of type size_t, which is probably a typedef for unsigned int for your case. Then you are comparing a signed int (i) and unsigned int (strlen(...)). C decides then to cast your signed value to an unsigned type (because of default type promotions). -6 converted to unsigned int is 4294967290, therefore your comparison is false, so the loop ends.
To fix this, you can for example cast strlen to a signed value, e.g.:
i < (int) strlen(fragments[1])
In a for-loop, the codition (the i < strlen(fragments[1]) part) gets evaluated on every iteration. If OverlapStrength changes the value of fragments[1] to something less than i, the loop will abort.
To fix this, use a constant:
int loopUntil = strlen(fragments[1]);
for (int i = -strlen(fragments[2]) + 1; i < loopUntil; i++) {
int test = OverlapStrength(fragments[1], fragments[2], i, 0);
printf("%d\n", test);
}

Resources