【问题标题】:Understanding this program which prints a sentence in reverse but keeps the words unchanged理解这个程序,它反向打印一个句子但保持单词不变
【发布时间】:2021-03-18 15:10:47
【问题描述】:

我不太了解这个程序。我不明白 for 循环中发生了什么。谁能用简单的话给我解释一下。而且该网站也没有很好地解释它。这是该网站的链接。 https://www.geeksforgeeks.org/print-words-string-reverse-order/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
void printReverse(char str[])
{
    int length = strlen(str);
    FILE *fptr;
    if((fptr=fopen("Question1.txt","w"))==NULL)
    {
        printf("Invalid file");
        exit(0);
    }


    int i;
    for (i = length - 1; i >= 0; i--) {
        if (str[i] == ' ') 
        {
 
            str[i] = '\0';
 
            printf("%s ", &(str[i]) + 1);
            fprintf(fptr,"%s ", &(str[i]) + 1);
        }
    }

    fprintf(fptr,"%s",str);
    printf("%s.", str);

    fclose(fptr);
}

int main()
{
    char str[1000];
    //clrscr();

    printf("Enter string: ");
    scanf("%[^\n]s", str);

    printReverse(str);

    //getch();
    return 0;
}

for 循环中,为什​​么要放入&amp;(str[i])+1?还有printf("%s.", str)--这只有第一个字;怎么样?

【问题讨论】:

  • edit您的问题并告诉我们您在理解链接网页上的解释时有什么困难。链接页面甚至包含带有解释性 cmets 的 C 代码。
  • 您链接的文章用非常简单的术语解释了它。我不认为这里的任何人都可以让它变得更简单。它从字符串的末尾循环到开头寻找空格字符。如果它找到一个空格,它首先通过用字符串结尾标记替换空格来修改字符串,然后打印它刚刚循环的单词。重复。循环退出后,它会打印第一个单词(因为第一个单词之前可能没有空格)。请注意,它会同时打印到标准输出和文件。
  • 进行了必要的更改@bodo
  • this only has the first word how? 因为第一个空格字符 ' ' 被替换为空终止符 '\0'。当您打印 c 字符串时,操作在第一个空终止符处结束
  • 哦好吧好吧。非常感谢。 @drescherjm

标签: arrays c loops for-loop


【解决方案1】:

好的,看看我能不能帮忙。我会仔细阅读代码。

我怀疑你已经明白了。这只是一个方法调用。

void printReverse(char str[])
{

strlen 是一种标准方法,它返回以空字符结尾的字符串的长度。这意味着 str 可能包含 Hello(5 个字符),但其中还有一个字节为 0,这就是 C 一直标记字符串结尾的方式。在这种情况下,str 本身占用 6 个字节,但长度为 5。

    int length = strlen(str);

这就是您在 C 中打开文件的方式。C++ 有更好的方法。文件是为写而写的。

    FILE *fptr;
    if((fptr=fopen("Question1.txt","w"))==NULL)
    {
        printf("Invalid file");
        exit(0);
    }

这是你的 for 循环。假设 str 包含 Hello,因此长度为 5,但字符串的索引为 str[0..4]。 C 使用索引作为“从开始的偏移量”,所以第一个元素是 0,而不是 1。因此,当这个循环开始时,str[i] == o(使用Hello 作为我们的示例字符串)。然后我们循环,每次递减i。一旦i 低于 0,循环结束。

    int i;
    for (i = length - 1; i >= 0; i--) {

好的,请记住我们按正常顺序打印单词,但单词本身的顺序是相反的。所以这会在单词之间寻找一个空格。因此,如果我们使用Hello there 作为输入文本,当i 指向两个单词之间的空格时,这个if 语句为真。

现在这是诀窍。还记得我之前说过的关于以空字符结尾的字符串吗?它的作用是踩到该空间并将其替换为 0。这使其余的魔术起作用。

        if (str[i] == ' ') 
        {
 
            str[i] = '\0';

这就是魔法。现在,这是一种奇怪的方法。我会用&amp;str[i+1] 完成它,但这有效。这是在说“打印在我们刚刚破坏的空间之后开始的字符串”。我们对终端和文件执行此操作。

            printf("%s ", &(str[i]) + 1);
            fprintf(fptr,"%s ", &(str[i]) + 1);
        }
    }

这会将生成的重新排列的字符串写入已打开的文件以及您的终端,然后确保文件已关闭。

    fprintf(fptr,"%s",str);
    printf("%s.", str);

    fclose(fptr);
}

这一切都有效,因为我们踩到了零。对于Hello world,我们:

  1. 从尾巴开始
  2. 找到空格并在其中粘贴一个零
  3. 打印world
  4. 继续备份到数据的末尾。
  5. 退出 for 循环并打印剩下的内容:Hello

【讨论】:

  • 非常感谢。我应该通过提到我不理解&amp;(str[i]) + 1 部分来让自己清楚一点。你是说&amp;str[i+1]&amp;str[i]+1 一样吗?如何?为什么放一个 & 那里?字符串不是指向它自己的地址吗?
  • @SuburbanBourbon,谷歌“指针算术”寻求帮助。在这种情况下,将 1 添加到索引或 ptr 会导致相同的结果,只是因为指针指向大小为 1(1 字节)的数据,即 char。例如,如果它指向一个 4 字节的数据,给指针加 1 与将索引增加 4 是一样的,这将是非常不同的。
  • @GabrielStaples 谢谢你告诉我。我会调查的
  • @GabrielStaples 还有一件事为什么要放&?字符串数组是否指向它自己的地址或类似的东西,如果我错了,请纠正我。
  • 再次感谢@GabrielStaples
【解决方案2】:

回答您的具体问题

为什么要在for循环中放? &amp;(str[i])+1?

&amp;str[i] 是索引i 处的字符的地址,其中空格已替换为NUL 字符。使用+1,您将获得其后字符的地址,即刚刚替换的空格后面的单词的开头。 (如果是双空格,这将导致一个空字符串。)

而且在printf("%s.", str); 这个只有第一个字怎么办?

假设第一个单词前面没有空格,则循环不会打印它。

这个printf("%s.", str); 将从头开始打印字符串,直到第一个 NUL 字符替换前一个空格字符,从而产生第一个单词。

评论中的其他问题

所以...例如,如果我输入 Hello World,那么其中的 W 是否会获得索引 0?

W 位于索引 6 处。(H 为 0,e 为 1,以此类推)

i 倒计时到 5 时,该位置的空格将被替换为 NUL ('\0') 字符,并将打印从 W 到结尾的剩余字符串也由 NUL 字符标记的字符串。 (由 C 标准定义。)

如果字符不是 NULL 字符怎么办?如果对的话,它就不会执行?它只会再次增加 i 直到遇到另一个 NULL 对吗?

我不完全理解这些问题。如果字符串末尾没有 NUL 字符,printf 会读到字符串末尾之后导致未定义的行为。

如果输入字符串Hello World and Universe", all spaces after Worldwould have been replaced with NUL characters before, so when the program reaches the position of the space beforeWorld`,则字符串为

Hello World\0and\0Universe\0

替换前和

Hello\0World\0and\0Universe\0

更换后。

【讨论】:

    猜你喜欢
    • 2022-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多