Search code examples
cfor-loopc-strings

Why does p+1 not produce the same result as p++ in this scenario?


Prompt: Write the following function: void get_extension(char *file_name, char *extension); file_name points to a string containing a file name. The function should store the extension on the file name in the string poinLed to by extension. For example, if the file name is memo.txt, the function will store "txt" in the string pointed to by extension. If the file name doesn't have an extension, the function should store an empty string (a single null character) in the string pointed to by extension.

//Version 1
#include <stdio.h>
#include <stdlib.h>

void get_extension(char *file_name, char* extension);

int main(){
    char file_name[1000], extension[10];
    printf("Enter file name: ");
    scanf("%s", file_name);

    get_extension(file_name, extension);

    printf("%s", extension);

    return 0;
}

void get_extension(char *file_name, char *extension){
    char *p;

    for(p = file_name; *p != '.'; p++);
    for(p++; *p != '\0'; p++, extension++){ //only difference between V1 and V2
        *extension = *p;
    }
    *extension = '\0';
}
//Version 2
#include <stdio.h>
#include <stdlib.h>

void get_extension(char *file_name, char* extension);

int main(){
    char file_name[1000], extension[10];
    printf("Enter file name: ");
    scanf("%s", file_name);

    get_extension(file_name, extension);

    printf("%s", extension);

    return 0;
}

void get_extension(char *file_name, char *extension){
    char *p;

    for(p = file_name; *p != '.'; p++);
    for(p+1; *p != '\0'; p++, extension++){ // only difference between V1 and V2
        *extension = *p;
    }
    *extension = '\0';
}

Why does version 1 work and version 2 not work? I know it has something to do with the p+1 and p++.


Solution

  • The initialization step in the "for" loop (p+1) really is not performing any incrementation of the memory location. It is merely evaluating to some numeric value. The first clue to this probably was with a compiler warning such as the one I got when compiling the program.

    /home/craig/C_Programs/Console/FileExtension/main.c|44|warning: statement with no effect [-Wunused-value]|
    

    My guess is that you also received that warning when compiling "version 2" of your program.

    With that in mind, I built a hybrid version of your program to call both versions of the "get_extension" function so as to compare the output data and hopefully clarify for you what is happening. Following is a refactored version of your program enabling the calling of both versions of the function.

    #include <stdio.h>
    #include <stdlib.h>
    
    void get_extension(char *file_name, char* extension);
    void get_extension2(char *file_name, char* extension);
    
    int main()
    {
        char file_name[1000], extension[10];
        printf("Enter file name: ");
        scanf("%s", file_name);
    
        get_extension(file_name, extension);
    
        printf("Extension is %s\n", extension);
    
        get_extension2(file_name, extension);
    
        printf("Extension is %s\n", extension);
    
        return 0;
    }
    
    void get_extension(char *file_name, char *extension)
    {
        char *p;
    
        for(p = file_name; *p != '.'; p++);             /* Starting at the beginning character array memory location, increment until the "." character is reached              */
    
        for(p++; *p != '\0'; p++, extension++)          /* The file character array pointer is in effect incremented, and then incremented in synch with the extension pointer  */
        {
            printf("p in first function is.: %p\n", p);
            *extension = *p;
        }
        *extension = '\0';
    }
    
    void get_extension2(char *file_name, char *extension)
    {
        char *p;
    
        for(p = file_name; *p != '.'; p++);             /* Starting at the beginning character array memory location, increment until the "." character is reached              */
    
        for(p+1; *p != '\0'; p++, extension++)          /* A value is calculated but not used and then the two pointers are incremented in synch which then includes "."        */
        {
            printf("p in second function is: %p\n", p);
            *extension = *p;
        }
        *extension = '\0';
    }
    

    The key bits to note are as follows:

    • In the first version of the function, once the location of the "." character is located, the initialization step within the second "for" loop increments the memory position ahead one position which effectively gets past the "." character and copies the remaining characters of the file name into the extension character array.
    • In the second version of the function, once the location of the "." character is located, the initialization step with the second "for" loop is just calculating a value which is not actually being used (and for which a compiler warning was received), so the "." character along with the remaining file name characters are copied into the extension character array.
    • To make the contrast between the two versions of the function stand out, a "printf" statement with the memory positions listed was added.

    Following is a sample execution of the program denoting the difference in function.

    craig@Vera:~/C_Programs/Console/FileExtension/bin/Release$ ./FileExtension 
    Enter file name: sample.txt
    p in first function is.: 0x7ffeda0b2e57
    p in first function is.: 0x7ffeda0b2e58
    p in first function is.: 0x7ffeda0b2e59
    Extension is txt
    p in second function is: 0x7ffeda0b2e56
    p in second function is: 0x7ffeda0b2e57
    p in second function is: 0x7ffeda0b2e58
    p in second function is: 0x7ffeda0b2e59
    Extension is .txt
    

    So the takeaway is in understanding how and when memory locations are incremented, decremented, and referenced, and to also check for clues and possible warnings within the compiler text. As always, you may want to reference some tutorial literature focusing in on arrays, their pointers, and pointer incrementing/decrementing.