C语言中的“写入访问冲突”是什么意思,我该如何解决这个问题?

What means "write access violation" in C and how do I solve this?

提问人:OldCrow 提问时间:7/1/2023 最后编辑:OldCrow 更新时间:7/1/2023 访问量:69

问:

所以我对 C 语言完全陌生。我有 Visual Basic 和 C# 的背景,在这些语言中,我通常不需要关心低级的东西。最近开始学习指针,我正在做一些 leetcode 挑战来练习。

**这里是挑战文字:** 编写一个函数以查找字符串数组中最长的公共前缀字符串。 如果没有通用前缀,则返回空字符串 “”。

这是我的尝试:

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

char* longestCommonPrefix(char** strs, int strsSize) {
    if (strsSize == 1) return strs[0];

    if (strs[0] == "") return "";

    char* result = strs[0];
    size_t result_length = strlen(result) - 1;
    char* result_end = strs[0] + result_length;

    for (size_t i = 1; i < strsSize; ++i) {
        
        size_t length = strlen(strs[i]) - 1;
        
        if (length < 1) return "";
        
        if (length < result_length) {
            result_end = strs[0] + length;
            result_length = length;
        }

        char* temp1 = result;
        char* temp2 = strs[i];

        while (*temp1 == *temp2 && temp1 < result_end) {
            ++temp1;
            ++temp2;
        }

        if (temp1 < result_end) {
            result_end = temp1 - 1;
            result_length -= strlen(result_end) - 1;
        }
    }

    *(result_end + 1) = '\0';
    
    return result;
}


int main(int argc, char* argv[]) {
    char* a[3];
    a[0] = "flower";
    a[1] = "flight";
    a[2] = "flow";

    char* b = longestCommonPrefix(a, 3);
    printf(b);
}

为什么我在线路上收到写入访问冲突错误? 在谷歌上搜索这个,我发现文章说 c 字符串是只读的,为什么呢,有什么解决方法? 此外,任何通用的 C 提示或指向此类内容的链接也值得赞赏,谢谢。*(result_end + 1) = '\0';

编辑:感谢@Chris的解决方案。 这是我的新代码,它工作得很好。还要感谢 @@WeatherVane 的一般 C 技巧,我还将他的知识包含在我的新代码中。

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

char* longestCommonPrefix(char** strs, int strsSize) {
    if (strsSize == 1) return strs[0];

    if (strs[0][0] == 0) return "";

    char* result = _strdup(strs[0]);
    size_t result_length = strlen(result) - 1;
    char* result_end = strs[0] + result_length;

    for (size_t i = 1; i < strsSize; ++i) {

        char* str = _strdup(strs[i]);
        
        size_t length = strlen(str) - 1;
        
        if (length < 1) return "";
        
        if (length < result_length) {
            result_end = str + length;
            result_length = length;
        }

        char* temp = result;

        while (*temp == *str && temp < result_end) {
            ++temp;
            ++str;
        }

        if (temp < result_end) {
            result_end = temp - 1;
            result_length -= strlen(result_end) - 1;
        }
    }

    *(result_end + 1) = '\0';
    
    return result;
}


int main(int argc, char* argv[]) {
    char* a[3];
    a[0] = "flower";
    a[1] = "flight";
    a[2] = "flow";

    char* b = longestCommonPrefix(a, 3);
    printf(b);
}


c 字符串 指针 char

评论

1赞 Weather Vane 7/1/2023
我没有收到编译器警告,程序打印 .但这不是在 C 中比较字符串的方法。您必须使用或在这种情况下检查flif (strs[0] == "")strcmp()if (strs[0][0] == 0)
0赞 OldCrow 7/1/2023
@WeatherVane 也许你有不同的编译器,我使用 Visual C(Visual Studio)。并感谢您提供字符串比较的提示。
0赞 Weather Vane 7/1/2023
使用 MS Visual C 64 位 2022(无 IDE)。

答:

0赞 Chris 7/1/2023 #1

这意味着你已经写入了一些你不应该写入的内存。

你有一个指针数组。但每个都指向一个字符串文字,即 .maincharconst char *

然后,尝试修改这些字符串文本,这将调用未定义的行为longestCommonPrefix

如果您希望在函数中修改这些值,则应将这些字符串文字复制到分配的内存中。strdup 是一种非常简单的方法,只要您确保事后释放动态分配的内存即可。longestCommonPrefix

char *a[3];
a[0] = strdup("flower");
a[1] = strdup("flight");
a[2] = strdup("flow");

如果你的工具不允许使用此函数,你可以声明保存 3 个固定长度的字符串,或者手动处理动态内存分配和复制。a

评论

1赞 Eric Postpischil 7/1/2023
由于遗留原因,C 语言中字符串文字的类型是 的数组 ,而不是 ,并且在适当的情况下,它会自动转换为 、 not 。不应该教学生期望,因为他们不能依赖编译器通过类型限定符捕获错误。C 标准不定义程序尝试修改字符串文本时的行为。这意味着在可移植代码中可以避免使用它,但这也意味着 C 实现可以支持修改字符串文字,如果其实现者需要。charconst charchar *const char *const char *
1赞 Chris 7/1/2023
使用 UB 代码可能做的最危险的事情:按预期工作。
1赞 Jonathan Leffler 7/1/2023
请注意,这在 C23 中成为标准 C 的一部分(也是如此)。strdup()strndup()
0赞 OldCrow 7/1/2023
感谢大家提供的信息。@Chris您的解决方案工作正常,但是对于leetcode挑战,我无法访问main,因此我只是将其添加到函数中。此外,我收到一个警告 strdup 已弃用,我应该使用_strdup因为它是 ISO 标准。无论如何,非常感谢你。为了清楚起见,我将把我的新代码添加到问题中。