为什么在这种情况下,p+1 不会产生与 p++ 相同的结果?

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

提问人:Dylan Girrens 提问时间:10/19/2023 更新时间:10/19/2023 访问量:69

问:

提示:编写以下函数: void get_extension(char *file_name, char *extension); file_name指向包含文件名的字符串。该函数应存储扩展 在字符串 poinLed to 中的文件名上,通过扩展名。例如,如果文件名 是 memo.txt,该函数会将“txt”存储在扩展指向的字符串中。如果 文件名没有扩展名,函数应存储一个空字符串(单个 null 字符)。

//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';
}

为什么版本 1 有效而版本 2 不起作用?我知道这与 p+1 和 p++ 有关。

for 循环 C 字符串

评论

4赞 CherryDT 10/19/2023
因为修改并且不修改(它计算 p+1 并返回结果,但你从不使用结果,所以它什么都不做)。如果你把它改成,它将再次相同。p++pp+1p+=1
1赞 Costantino Grana 10/19/2023
请注意,这两种解决方案都假定字符串中存在“.”,这绝对不是问题语句所保证的。
1赞 Neil 10/19/2023
建议 strrchr
1赞 greg spears 10/19/2023
旁注 -- 如果文件名中有多个点“.”,则 get_extension() 将不会获得扩展名。这可能是 @neil 推荐 strrchr() 的至少一个原因

答:

0赞 NoDakker 10/19/2023 #1

“for”循环 (p+1) 中的初始化步骤实际上没有执行内存位置的任何增量。它只是计算到某个数值。第一个线索可能是编译器警告,例如我在编译程序时收到的警告。

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

我的猜测是,您在编译程序的“版本 2”时也收到了该警告。

考虑到这一点,我构建了一个混合版本的程序来调用两个版本的“get_extension”函数,以便比较输出数据,并希望为您澄清正在发生的事情。下面是程序的重构版本,允许调用函数的两个版本。

#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';
}

需要注意的关键点如下:

  • 在函数的第一个版本中,一旦找到“.”字符的位置,第二个“for”循环中的初始化步骤就会将内存位置递增到前面一个位置,从而有效地越过“.”字符,并将文件名的剩余字符复制到扩展字符数组中。
  • 在函数的第二个版本中,一旦找到“.”字符的位置,第二个“for”循环的初始化步骤只是计算一个实际未使用的值(并且收到了编译器警告),因此“.”字符以及剩余的文件名字符被复制到扩展字符数组中。
  • 为了突出两个版本的函数之间的对比,添加了一个“printf”语句,其中列出了内存位置。

以下是表示功能差异的程序执行示例。

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

因此,要点在于了解内存位置如何以及何时递增、递减和引用,并检查编译器文本中的线索和可能的警告。与往常一样,您可能希望参考一些侧重于数组、其指针和指针递增/递减的教程文献。