Visual Studio 在修改传递到函数中的指针时C++访问冲突

Visual Studio C++ access violation when modifying a pointer passed into a function

本文关键字:指针 访问冲突 C++ 函数 Studio 修改 Visual      更新时间:2023-10-16

我想实现一个简单的函数,该函数获取字符串作为字符指针并在函数中修改字符串。请求的函数必须是 void,然后我必须修改传递给我的函数的主要字符串。我收到一个访问违规错误并在谷歌上搜索了它,但没有任何帮助。

我的示例代码在这里:

#include "iostream"
using namespace std;
void FindCommonStr(char*& Common,int &A)
{   
    int i=0;
    while(1)
    {
        if(Common[i]=='')
            break;
        i++;
    }
    cout<<"Number of Elements = "<<i<<endl;
    for (int j=0 ; j<i-1;j++)   
        Common[j]='y';      
    A=2;    
}
void main()
{
    int A=0;    
    char* Common = new char;
    Common = "Hello World!";
    cout<<"Common0 = "<< Common<<endl;
    cout<<"A0 = "<< A<<endl;
    FindCommonStr(Common,A);    
    cout<<"Common1 = "<< Common<<endl;
    cout<<"A1 = "<< A<<endl;
}

实际上,问题发生在FindCommonStr功能的这一部分:

for (int j=0 ; j<i-1;j++)   
            Common[j]='y';

如果我评论这部分,一切正常,但我无法更改字符串值。我还通过将函数定义为:

FindCommonStr(char **Common,...

不过这没有帮助,我再次收到违规错误。甚至有可能做这样的事情吗?

当你这样做时:

Common = "Hello World!";

您正在使指针Common指向文字 C 样式字符串(并顺便泄漏您之前通过 new 分配的原始char)。尝试修改此类文本是无效的,因此当您将其传递给FindCommonStr并尝试修改它时,您将获得访问冲突。

您应该避免使用 C 样式字符串并使用适当的C++ std::string - 这将节省很多问题,并且更加健壮,并且更适合C++编程。

代码的固定版本:

#include <iostream>
#include <string>
using namespace std;
static void FindCommonStr(string &Common, int &A)
{
    int i = 0;
    while (1)
    {
        if (Common[i] == '')
            break;
        i++;
    }
    cout << "Number of Elements = " << i << endl;
    for (int j = 0; j < i - 1; j++)
        Common[j] = 'y';
    A = 2;
}
int main()
{
    int A = 0;
    string Common = "Hello World!";
    cout << "Common0 = " << Common << endl;
    cout << "A0 = " << A << endl;
    FindCommonStr(Common, A);
    cout << "Common1 = " << Common<<endl;
    cout << "A1 = " << A << endl;
    return 0;
}

或者,如果这是一个家庭作业,由于某种深不可测的原因,您需要使用 C 字符串,那么仅使用char *字符串的固定版本可能如下所示:

#include <iostream>
using namespace std;
static void FindCommonStr(char *Common, int &A)
{
    int i = 0;
    while (1)
    {
        if (Common[i] == '')
            break;
        i++;
    }
    cout << "Number of Elements = " << i << endl;
    for (int j = 0; j < i - 1; j++)
        Common[j] = 'y';
    A = 2;
}
int main()
{
    int A = 0;
    char Common[] = "Hello World!";
    cout << "Common0 = " << Common << endl;
    cout << "A0 = " << A << endl;
    FindCommonStr(Common, A);
    cout << "Common1 = " << Common<<endl;
    cout << "A1 = " << A << endl;
    return 0;
}

这部分在概念上是错误的:

char* Common = new char;
// 'Common' is set to point to a piece of allocated memory
// (typically located in the heap)
Common = "Hello World!";
// 'Common' is set to point to a constant string
// (typically located in the code-section or in the data-section)

您分配变量Common两次,因此显然,第一次赋值没有任何意义。

这就像写作:

int i = 5;
i = 6;

最重要的是,您"丢失"了分配的内存块的地址,因此您将无法在程序执行的稍后点释放它。

你似乎混淆了 char[] 和字符串

当你写的时候

char* Common = new char; 

您可以在堆上为Common指向的一个字符分配空间。

然后你写

Common = "Hello World!";

它将指针 Common 设置为指向只读内存中的字符串"Hello World"。您之前分配的堆现在已泄露。

基本上有两种方法:

要么你使用字符数组,在这种情况下,你写的东西像

char* Common = new char[strlen("Hello World!")+1];
strcpy(Common, "Hello World!");

现在 common 仍然指向堆,字符串已复制到那里。额外的 +1 字节用于保存结尾 \0 字符串终止符。

完成后,您需要释放内存公共点。

delete Common;

另一种方法是使用字符串模板

std::string Common;

这允许您分配一个字符串,它囊括了上面堆数组的所有工作。

Common = "Hello World!";

之后无需删除任何内容,因为 std::string 会为您执行此操作。