【问题标题】:Invoking the function renders an error; what explains this?调用该函数会导致错误;这是什么解释?
【发布时间】:2021-11-03 14:19:48
【问题描述】:

我创建的一个函数,我称之为string_deletion,删除特定子字符串的出现并将字符串向左移动子字符串的长度。该函数接受两个参数:指向数组中遇到子字符串第一个字母的位置的指针,以及单词的长度。

函数如下:

void string_deletion(char *s, int m)
{
    char *index=s+m;
    while(*index!=0)
    {
        *(index-m)=*(index++);
    }
    *(index-m)=0;
}

该函数将子字符串之后的所有字符向左移动一个取决于子字符串长度的量,该长度由m 表示。我已将index 指针设置为指向子字符串出现后立即出现的字符,这就是移位开始的标记。循环一直执行,直到遇到NUL 字符,然后退出循环。最后,NUL 被附加到字符串的末尾。

虽然主代码的其他部分无缝工作,但在必要时调用此特定函数会使程序停止工作并产生错误。这是什么原因?

这是完整的代码:

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

int string_len(char *s)
{
    int i=0;
    char *m=s;
    while(*m!=0)
    {
        i++;
        m++;
    }
    return i;
}
void word_enter(char *word_search)
{
    char r;
    char *m=word_search;
    while((r=getchar())!=EOF)
    {
        if(r=='\n')
        {
            *m=0;
            break;
        }
        else
        {
            *(m++)=r;
        }
    }
}
 
void string_disp(char *s)
{
    char *d=s;
    while(*d!=0)
    {
        putchar(*(d++));
    }
}

int string_comp(char *s, char *m)
{
    int stringlength_one=string_len(s);
    int stringlength_two=string_len(m);
    char *s_one=s;
    char *s_two=m;
    if(stringlength_one!=stringlength_two)
    {
        return 1;
    }
    else
    {
        while(*s_one!=0)
        {
            if(*s_one!=*s_two)
            {
                return 1;
            }
            s_one++;
            s_two++;
        }
    }
    return 0;
}

void string_deletion(char *s, int m)
{
    char *index=s+m;
    while(*index!=0)
    {
        *(index-m)=*(index++);
    }
    *(index-m)=0;
}

void string_search(char *s,char *d)
{
    char *m=s;
    char word_buffer[20];
    char *buffer_index=word_buffer;
    while(m!=&s[string_len(s)-string_len(d)+1])
    {
        buffer_index=word_buffer;
        if(*m==*d)
        {   
            int i=0;
            char *r=m;
            while(i<=string_len(d) && *r!=0)
            {
                *(buffer_index++)=*(r++);
                i++;
            }
            *buffer_index=0;
            if(string_comp(word_buffer,d)==0)
            {
                printf("\nInvoking deletion sequence\n");
                string_deletion(m,string_len(d));
            }
        }
    m++;
    }
}   
    
int main(void)
{
    int pos;
    char main_string[100],word[20];
    printf("Enter the main string: ");
    word_enter(main_string);
    printf("\nEnter the string you wish to delete: ");
    word_enter(word);
    string_search(main_string,word);
    string_disp(main_string);
    exit(EXIT_SUCCESS);
}

【问题讨论】:

  • 请显示minimal reproducible example。问题可能出在调用代码中。
  • 您是否将字符串文字传递给您的函数?也就是说,您是否有类似:char* test = "I am a string literal"; 然后使用 test ... 这意味着您正在尝试修改不可变(常量)字符串。
  • m!= 应该是 m&lt;,因为字符串长度可以变化不止一。
  • while((r=getchar())!=EOF) 这是错误的(但与您的问题无关)。 getchar 返回 int,而不是 char。 char 可能根本无法保存 EOF 的值。
  • getchar 返回一个int。不是wchar_t。你应该使用int,而不是wchar_t。

标签: arrays c function pointers


【解决方案1】:

我不会重新发明轮子:

char *string_deletion(char *s, size_t m)
{
    memmove(s, s + m, strlen(s+m) + 1);
    return s;
}

【讨论】:

    【解决方案2】:

    问题(或至少一个问题)出在您的string_search 函数中。您从给定的s 参数中提取的子字符串是一个字符太长;因此,除非您非常幸运,否则您不会得到与给定 d 参数的匹配。

    要解决此问题,请将while 循环中的测试条件从i &lt;= string_len(d) 更改为i &lt; string_len(d),如下所示:

    void string_search(char* s, char* d)
    {
        char* m = s;
        char word_buffer[20];
        char* buffer_index = word_buffer;
        while (m != &s[string_len(s) - string_len(d) + 1]) {
            buffer_index = word_buffer;
            if (*m == *d) {
                int i = 0;
                char* r = m;
                while (i < string_len(d) && *r != 0) { // Use i < string_len ... not i <=
                    *(buffer_index++) = *(r++);
                    i++;
                }
                *buffer_index = 0;
                if (string_comp(word_buffer, d) == 0) {
                    printf("\nInvoking deletion sequence\n");
                    string_deletion(m, string_len(d));
                }
            }
            m++;
        }
    }
    

    另外,一定要解决this answer 中突出显示的未定义行为问题(我的 MSVC 编译器没有发现那个问题,但 clang-cl 发现了)!

    【讨论】:

    • 嗯,怎么会?例如,如果我要删除的子字符串是 5 个字符长,那么我想缓冲区也会输入 5 个字符,不是吗?
    • 是的。但是你从 zero 开始计数(你应该这样做);所以,当i == 5 你复制了六个个字符。试试我所做的:在 string_comp 函数的顶部放置一行,打印出它给出的两个字符串 - 你会看到第一个字符比第二个长一个字符。
    • 这修复了一个错误。来自@n 的答案。 1.8e9-where's-my-share m.,专门解决函数string_deletion中的bug。
    • @JonathonS。确实是的。这就是为什么我添加脚注,链接到那个答案。我本可以自己提供一个解释,但这对于剽窃来说是最重要的,因为他们在我意识到错误存在之前就发布了他们的答案。
    • @AdrianMole,这是有道理的。我真傻!
    【解决方案3】:
    *(index-m)=*(index++)
    

    这是未定义的行为。如果您使用后置或前置递增/递减,请不要在同一个表达式中再次使用同一个变量。

    index[-m] = *index;
    ++index;
    

    【讨论】:

    • 好地方! MSVC 错过了,但 clang-cl 看到了。
    • 在这种情况下,*(index-m) 等价于 index[-m],是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    相关资源
    最近更新 更多