反转文件中的单词

时间:2018-08-01 21:35:29

标签: c

有人可以向我提示我在做什么错吗?我尝试编译它,但不确定在这里出了什么问题

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main()
{
  int k, i, j, len;
  FILE *f;
  char aux, str[100];

  f = fopen("rev.txt", "r");
  len = strlen(str);
  if (f == NULL) {
    printf("File not found!");
    return 0;
  }

  while (fgets(str, 80, f) != NULL) {
    for (j = 0; j < len; j++)
      if ((isalpha(str[j]) != 1) || (j == len - 1))
        if (j < len - 1)
          k = j - 1;
        else
          k = j;
    i = 0;
    while (i < k) {
      aux = str[i];
      str[i] = str[k];
      str[k] = aux;
      i++;
      k--;
    }

    printf("%s",str);
  }
}

因此,在上面的代码中,我尝试了反转名为rev的文件中的单词,但是无论何时运行它,它都会打印出奇怪的字符。有帮助吗?

1 个答案:

答案 0 :(得分:5)

正确缩进代码,然后打开警告,即可发现问题所在。您正在使用forif,但没有阻止。尽管这是合法的,但很容易出错。特别是...

    for(j=0;j<len;j++)
        if ((isalpha(str[j])!=1) || (j==len-1))
    if(j<len-1)
        k=j-1;
    else
        k=j;
    i=0;

老实说,我不确定这里合适的支撑是什么。我的编译器已警告"dangling else",因此有误。

test.c:21:9: warning: add explicit braces to avoid dangling else [-Wdangling-else]
        else

我怀疑你是这个意思。

    for(j=0;j<len;j++) {
        if((isalpha(str[j])!=1) || (j==len-1)) {
            if(j<len-1) {
                k=j-1;
            }
            else {
                k=j;
            }
        }
    }

无论哪种方式,请始终使用块。始终编​​译警告。我使用-Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic


这是另一个问题:

len = strlen(str);

此时str尚未初始化,因此将包含垃圾。 len将是该垃圾的长度。

len也将永远不会改变,但是str的内容会随着每一行的读取而改变。相反,您需要在每次str调用之后检查循环内fgets的长度。

while(fgets(str,80, f) != NULL) {
    len = strlen(str);
    ...
}

您的str缓冲区为100,但是您只允许fgets 80个字符。为避免这种情况,请使用sizeof(str)而不是硬编码。注意:这仅适用于堆栈分配的内存。

while(fgets(str, sizeof(str), f) != NULL) {
    len = strlen(str);

尽管您在使用它,但没有理由对行缓冲区感到小气。它只分配一次。对于行缓冲区,80或100很小。给它4096个字节以允许很长的行。


通过这些修复,您的代码可以运行,但是我们可以对其进行改进。特别是整个for循环似乎是不必要的。我怀疑它正在做的所有事情都是试图将换行符保留在反向字符串的末尾。无需遍历整个字符串。 fgets逐行读取,如果有换行符,它将始终位于结尾。

// Convert the length to an index
k = strlen(str) - 1;

// Leave the trailing newline alone
if( str[k] == '\n' ) {
    k--;
}

有了它,加上更好的变量名,仅在需要时声明变量,并使用正确的类型,我们得到...

while(fgets(str, sizeof(str), f) != NULL) {
    // Check if someone snuck a null byte into the file.
    if( !*str ) {
        continue;
    }

    // Convert the length to an index
    size_t back = strlen(str) - 1;

    // Leave the trailing newline alone
    if( str[back] == '\n' ) {
        back--;
    }

    // Swap characters
    size_t front = 0;
    while(front < back) {
        char tmp   = str[front];
        str[front] = str[back];
        str[back]  = tmp;
        front++;
        back--;
    }

    printf("%s",str);
}

甚至可以使用指针而不是索引来简化此操作。

while(fgets(str, sizeof(str), f) != NULL) {
    // A pointer to the last character of str
    char *back = &str[strlen(str) - 1];

    // Leave the trailing newline alone
    if( *back == '\n' ) {
        back--;
    }

    // Swap characters
    for(
        char *front = str;
        front < back;
        front++, back--
    ) {
        char tmp = *front;
        *front   = *back;
        *back    = tmp;
    }

    printf("%s",str);
}