导致分段错误的原因是什么?

时间:2017-01-29 00:13:23

标签: c

当我运行我的代码并选择选项2或3时,在输入我的字符串后,我收到了分段错误错误,而且我看不出导致错误的原因。我假设我的加密和解密功能有问题,但我不确定是什么。

#include <stdio.h>
#include <string.h>
#define SIZE 500
int getUserChoice()
{
    int decision = 0;

    printf("-------------------------------\n");
    printf("| 1) Change Shift (default 3) |\n");
    printf("| 2) Encrypt a message        |\n");
    printf("| 3) Decrypt a message        |\n");
    printf("| 4) Quit                     |\n");
    printf("-------------------------------\n");
    printf("Option: ");
    scanf("%d", &decision);
    if(decision <= 0 || decision >= 4)
    {
        return 0;
    }

    return decision;
}
int getShift()
{
    int key = 3;
    printf("Enter new shift value: ");
    scanf("%d", &key);
    return key;
}
void getString(char buf[])
{
    char c = 0;
    int i = 0;
    while((c = getchar()) != '\n' && c != EOF){
    }
    printf("Input: ");
    fgets(buf, SIZE, stdin);
    printf("Output: %s\n", buf[i]);

} 
void encrypt(char buf[], int shift)
{
    int i;

    for(i = 0; i < (strlen(buf-1));++i)
    {

        buf[i] = buf[i] + shift;

    }

}
void decrypt(char buf[], int shift)
{
    int i;

    for(i = 0; i < (strlen(buf-1)); ++i)
    {

        buf[i] = buf[i] - shift;

    }

}
int main()
{
    char userStr[SIZE];
    int shift = 3;
    int number;
    while(1)
    {
         number = getUserChoice();
        if(number == 1)
        {
            shift = getShift();
        }
        if (number == 2)
        {
            getString(userStr);
            encrypt(userStr, shift);
        }
        if (number == 3)
        {
            getString(userStr);
            decrypt(userStr, shift);
        }
        if (number == 0)
        {
            break;
        }
    }
    return 0;

}

1 个答案:

答案 0 :(得分:1)

由于getString()函数中的这一行:

,您的程序崩溃了
printf("Output: %s\n", buf[i]);

buf[i]中存储的值是char,但您尝试使用%s转换规范进行打印,从而导致未定义的行为。 encrypt()decrypt()函数中也存在问题,您尝试查找strlen(buf - 1)。请记住,buf转换为表达式中char的指针,因此这是指针算术。如果指针算术运算的结果指向不在数组本身中的任何位置,或者指向数组末尾之外的任何位置,则行为未定义。所以你也有UB。我怀疑你的意思是strlen(buf) - 1,无论如何都不应该这样。

您应该重写getString()函数以从输入中删除尾随换行符,以便您不再需要担心它。此外,如果用户输入太多字符,输入流中会留下额外的字符,最好丢弃这些字符:

void getString(char buf[])
{
    int c;
    int i = 0;

    while ((c = getchar()) != '\n' && c != EOF)
        continue;                   // discard leading characters


    fgets(buf, SIZE, stdin);
    while (buf[i] != '\n' && buf[i] != '\0')
    {
        ++i;
    }

    if (buf[i] == '\n')             // replace newline with '\0'
    {
        buf[i] = '\0';
    } else {
        while ((c = getchar()) != '\n' && c != EOF)
            continue;               // discard extra characters
    }
}

此处,c被声明为int,以保留可能的EOF值。在调用fgets()之前有一个循环,用于删除先前调用scanf()的输入流中剩余的任何内容。获得输入后,有一个循环在输入中搜索\n个字符。如果找到,则换行符将替换为NUL终止符。否则,输入流中会有额外的字符,这些字符将被丢弃。

打印Input:Output:的代码已移至main(),应该显示,以便显示已转换的输入。

encrypt()decrypt()函数可以通过\0未转换的方式轻松改进:

void encrypt(char buf[], int shift)
{
    int i = 0;

    while (buf[i] != '\0')
    {
        buf[i] = buf[i] + shift;
        ++i;
    }
}

循环继续,直到遇到NUL字符,而不是使用计数来控制循环。

以下是修改后的代码:

#include <stdio.h>
#include <string.h>
#define SIZE 500

int getUserChoice(void)
{
    int decision = 0;

    printf("-------------------------------\n");
    printf("| 1) Change Shift (default 3) |\n");
    printf("| 2) Encrypt a message        |\n");
    printf("| 3) Decrypt a message        |\n");
    printf("| 4) Quit                     |\n");
    printf("-------------------------------\n");
    printf("Option: ");
    scanf("%d", &decision);
    if(decision <= 0 || decision >= 4)
    {
        return 0;
    }

    return decision;
}

int getShift(void)
{
    int key = 3;
    printf("Enter new shift value: ");
    scanf("%d", &key);
    return key;
}

void getString(char buf[])
{
    int c;
    int i = 0;

    while ((c = getchar()) != '\n' && c != EOF)
        continue;                   // discard leading characters


    fgets(buf, SIZE, stdin);
    while (buf[i] != '\n' && buf[i] != '\0')
    {
        ++i;
    }

    if (buf[i] == '\n')             // replace newline with '\0'
    {
        buf[i] = '\0';
    } else {
        while ((c = getchar()) != '\n' && c != EOF)
            continue;               // discard extra characters
    }
}

void encrypt(char buf[], int shift)
{
    int i = 0;

    while (buf[i] != '\0')
    {
        buf[i] = buf[i] + shift;
        ++i;
    }
}

void decrypt(char buf[], int shift)
{
    int i = 0;

    while (buf[i] != '\0')
    {
        buf[i] = buf[i] - shift;
        ++i;
    }
}

int main(void)
{
    char userStr[SIZE];
    int shift = 3;
    int number;
    while(1)
    {
         number = getUserChoice();
        if(number == 1)
        {
            shift = getShift();
        }
        if (number == 2)
        {
            printf("Input: ");
            getString(userStr);
            encrypt(userStr, shift);
            printf("Output: %s\n", userStr);
        }
        if (number == 3)
        {
            printf("Input: ");
            getString(userStr);
            decrypt(userStr, shift);
            printf("Output: %s\n", userStr);
        }
        if (number == 0)
        {
            break;
        }
    }
    return 0;

}

以下是一个示例互动:

-------------------------------
| 1) Change Shift (default 3) |
| 2) Encrypt a message        |
| 3) Decrypt a message        |
| 4) Quit                     |
-------------------------------
Option: 2
Input: hello world
Output: khoor#zruog
-------------------------------
| 1) Change Shift (default 3) |
| 2) Encrypt a message        |
| 3) Decrypt a message        |
| 4) Quit                     |
-------------------------------
Option: 3
Input: khoor#zruog
Output: hello world
-------------------------------
| 1) Change Shift (default 3) |
| 2) Encrypt a message        |
| 3) Decrypt a message        |
| 4) Quit                     |
-------------------------------
Option: 4