为什么此代码在编写异常时会引发Access违规?

时间:2015-02-22 04:19:06

标签: c

有谁知道为什么以下代码会引发访问冲突写入异常?

void squeeze_c(char s[], int c)
{
    int i, j;

    for (i = j = 0; s[i] != '\0'; i++)
    {
        if (s[i] != c)
            s[j++] = s[i];
        s[j] = '\0';
    }
}

我将该函数调用如下:

squeeze_c("Test", 's');

1 个答案:

答案 0 :(得分:1)

该代码没有任何内在错误,因此它归结为两种可能性(可能更多,但这些是我经验中最常见的)。

  1. 您传递的是非字符串,但未以\0字符终止。

  2. 您正在传递一个字符串 literal,您不允许修改的内容。

  3.   

    既然您已经明确表示您使用squeeze_c("Test", 's');进行了调用,则上面的第二点是正确的。


    前者是你做的事情:

    char str[] = {'n','o',' ','n','u','l',' ','h','e','r','e'};
    

    你可以通过简单地确定最后一个\0来解决这个问题。


    后者是你做的事情之一:

    squeeze_c("this is a literal", 'l');
    

    或:

    char *xyzzy = "another literal";
    squeeze_c(xyzzy, 'l');
    

    您可以通过确保您拥有文字的可写副本来修复 ,例如:

    char xyzzy[] = "another literal";
    squeeze_c(xyzzy, 'l');
    

    你真的没有想要在内循环中添加\0,因为它可能会损坏你的源代码串。

    考虑您是否使用:

    char xyzzy[] = "paxdiablo";
    squeeze_c (xyzzy, 'd');
    

    第一次循环播放时,您将用自己覆盖p,然后用a覆盖\0然后你&# 39; ll退出循环,因为在索引i找到的下一个字符将是你刚写入字符串的\0

    所以它不会删除所有d个字符,因为将整个字符串截断为一个长度。

    相反,你最好还是选择:

    void squeeze_c(char *s, int c) {
        int i, j;
        for (i = j = 0; s[i] != '\0'; i++)
            if (s[i] != c)
                s[j++] = s[i];
        s[j] = '\0';  // moved outside the loop
    }
    

    这会将字符串转换为如下(|代表\0):

    paxdiablo|     original string
    paxdiablo|     copy p over p
    paxdiablo|     copy a over a
    paxdiablo|     copy x over x
    paxdiablo|     no copy, j now one less than i
    paxiiablo|     copy i over d
    paxiaablo|     copy a over i
    paxiabblo|     copy b over a
    paxiabllo|     copy l over b
    paxiabloo|     copy o over l
    paxiablo||     final placement of \0