C 中下溢时损坏的 fgets 输入

Broken fgets input when underflow in C

我正在尝试制作一个字符串逆向程序。我正在尝试使用 over/underflow 修复错误。我修复了第一个,所以现在我设置 MAX = 8 只是为了更容易调试。 它工作正常。但是当我的输入比MAX短时,程序就崩溃了。

因此,如您所见,字符串“QWERTY ASDFGH”被正确剪切,我有“QWERTY A”(正好是 8 个字符),然后程序将其反转,输出为“A YTREWQ”。它完全符合我的要求。

但是如果实际长度小于8,我按回车,没有任何反应。我必须按两次,输入和输出仍然损坏。 输出换行,但这不是它必须的工作方式。

这是我的源代码:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

#define MAX 8 // not including '[=10=]' symbol

void printAsterisks(uint8_t);
void clearInputBuffer(void);

int main(void) {

    char word[MAX + 1], temp;
    int length, index;

    printAsterisks(46);
    printf("Please, type in any string. To exit give me #.\n");
    printAsterisks(46);

    while(1) {
        index = 0;
        printf("Your string : "); 

        fgets(word, MAX + 1, stdin);
            
        if(word[0] == '#') {
                printAsterisks(39);
                printf("The program has been cancelled by User.\n");
                printAsterisks(39);
                break;
        }

        clearInputBuffer();

        length = strlen(word);
            
        for(index = 0; index < length / 2; index++) {
                temp = word[index];
                word[index] = word[length - index - 1];
                word[length - index - 1] = temp;
        }

        printf("Reversed    : %s\n", word);
    }

    return 0;
}

void printAsterisks(uint8_t count) {
    for(uint8_t i = 0; i < count; i++) {
            printf("*");
    }
    printf("\n");
}

void clearInputBuffer(void) {
    static char buff;
    while((buff = getchar()) != '\n' && buff != EOF);
}

正如@Some programmer dude所说,clearInputBuffer函数无效,我稍微修改了一下。我假设你的意思是清除 word。我还使 wordtemp 全局化,并在解析字符串并反转它之后而不是之前调用 clearInputBuffer

#include <stdio.h>
#include <string.h>
#include <stdint.h>

#define MAX 8 // not including '[=10=]' symbol

char word[MAX + 1], temp;

void printAsterisks(uint8_t);
void clearInputBuffer(void);

int main(void) {
    int length, index;

    printAsterisks(46);
    printf("Please, type in any string. To exit give me #.\n");
    printAsterisks(46);

    while(1) {
        index = 0;
        

        fgets(word, MAX + 1, stdin);
        
        if(word[0] == '#') {
                printAsterisks(39);
                printf("The program has been cancelled by User.\n");
                printAsterisks(39);
                break;
        }
        
        length = strlen(word);
        
        for(index = 0; index < length / 2; index++) {
                temp = word[index];
                word[index] = word[length - index - 1];
                word[length - index - 1] = temp;
        }

        printf("Reversed    : %s\n", word);

        clearInputBuffer();
    }

    return 0;
}

void printAsterisks(uint8_t count) {
    for(uint8_t i = 0; i < count; i++) {
            printf("*");
    }
    printf("\n");
}

void clearInputBuffer() {
    int i;
    for (i = 0; word[i] != '[=10=]'; i ++) {
        word[i] = '[=10=]';
    }
}

问题是您试图刷新输入缓冲区。

fgets 调用读取缓冲区中的换行符,如果它适合

当您输入少于 MAX 个字符时,fgets 调用将读取换行符,但您仍然调用 clearInputBuffer,它将尝试读取直到 下一个换行。

您需要检查缓冲区 word 是否包含换行符,只有在没有换行符时才调用 clearInputBuffer

您可以使用 strcspn 函数来检查换行符,并使用其返回的位置来设置空终止符以从缓冲区中“删除”换行符:

// strcspn will return the beginning index of the sub-string you search for
// Or the index of the null-terminator if the sub-string wasn't found
size_t newline_pos = strcspn(word, "\n");

if (word[newline_pos] == '\n')
{
    // There's a newline in the input, remove it
    word[newline_pos] = '[=10=]';
}
else
{
    // There's no newline, skip the remainder of the line
    clearInputBuffer();
}