Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating string length not correct when not printing out the return value of a program

Length is suppose to return how far along the counter went when going trough the string. However, it only returns the correct value when it is printed beforehand. If i comment out the printf it returns 0. Does anyone have an explanation for this?

#include<stdio.h>
#include<string.h>
#define MAX 100

int length(char *s) {
    int i;
    for (i = 0; s[i] != '\0'; ++i)
        printf("%d ", i);           //<-- here
    return i;
}

int main() 
{
    char s[MAX];
    fgets(s, (char)sizeof(s), stdin);
    s[strcspn(s, "\n")]='\0';
    printf("Length: %d\n", length(s));
    return 0;
}
like image 546
ptushev Avatar asked Jan 04 '19 09:01

ptushev


Video Answer


3 Answers

The problem is, if you comment out the printf() statement in the length() function, the return statement becomes part of the loop body, and the very first iteration returns from the call and you get the the-then value of i, which is just the entry value for the loop, 0.

for (i = 0; s[i] != '\0'; ++i)
    //printf("%d ", i);           //<-- here
return i;                         // without brace-enfoced scope, this is the loop body.

is the same as

for (i = 0; s[i] != '\0'; ++i)
return i;                                

What You need is the loop to complete the execution, hit the exit criteria and then, execute the return statement with the latest value of i.

So, to avoid the problem, you can enforce empty execution of the loop, by something like

for (i = 0; s[i] != '\0'; ++i) ;   // notice the ; here, ends the scope.
return i; 

or, even better (for the readers)

for (int i = 0; i < 10; i++) 
    {/*nothing here*/}       //indicates empty loop body
return i;

Note: As an alternative way, to enhance the readability, instead of a for construct you can also make use of while loop, which goes like

while (s[i] != '\0') 
{
    i++;                     //increment statement is explicit.
}
like image 123
Sourav Ghosh Avatar answered Oct 31 '22 14:10

Sourav Ghosh


In a loop like this:

for (...)
    statement1;
statement2;

statement1 will be the only thing executed in the loop. When you comment out the printf call, return i; is executed on the very first iteration, immediately returning zero.

Notice, however, that statement1 can be empty, so, to run a loop with no body, do:

for (...)
    ; // yes, a hanging semicolon

// or like this:
for (...);
like image 25
ForceBru Avatar answered Oct 31 '22 12:10

ForceBru


If you just commnt out that printf, you will be left with this:

int length(char *s) {
    int i;
    for (i = 0; s[i] != '\0'; ++i)
    return i;
}

This is equal to:

int length(char *s) {
    int i;
    for (i = 0; s[i] != '\0'; ++i){
        return i; // returns in the first iteration, without even incrementing i once
    }
}

Surely this isn't what you intended. Instead, put a semicolon after the for loop:

for (i = 0; s[i] != '\0'; ++i);

This way, for (i = 0; s[i] != '\0'; ++i); won't accidentally affect a following statement.

You can prevent such accidents by adding explicit braces to denote your intention, for instance:

int length(char *s) {
    int i;
    for (i = 0; s[i] != '\0'; ++i) {
        printf("%d ", i);           //<-- here
    }
    return i;
}

Now if you remove the printf line, it doesn't affect the program execution in any other way than omitting the print.

like image 20
Blaze Avatar answered Oct 31 '22 13:10

Blaze