I wrote a simple test program in c++ but why does this crash on:
s[i] = s[i] - 'a' + 'A';
with the exception: Access violation writing location 0x01327808
#include "stdafx.h"
#include <iostream>
using namespace std;
class String
{
public:
char *s;
int len();
void upper();
String(char*);
};
String开发者_运维技巧::String(char*x)
{
s = x;
}
int String::len()
{
return strlen(s);
}
void String::upper()
{
for (int i = 0; i < len(); i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
{
cout << s[i] << endl;
s[i] = s[i] - 'a' + 'A';
}
}
};
int main()
{
String s("test");
s.upper();
cout << s.len() << endl;
cout << s.s << endl;
system("pause");
}
It's because of:
String s("test");
What this does is to pass the const char *
"test"
to your constructor which then simply stores the address of that string.
Later, when you try to modify the memory that the pointer points to, that's undefined behaviour.
Typically, string literals will be stored in read-only memory to allow certain optimisations to take place, and any attempt to modify them will result in a access violation.
If you were to change:
String s("test");
into:
char cp[] = "test";
String s(cp);
you may well find it will work.
However, your class should really be making a copy of the string for its own purposes - a mere pointer is unsafe, since the code that passed you that pointer can change the contents of it as well.
Things you should change in your code to make it safer:
s
should be a private member, not a public one.- your constructor should make its own copy of the string:
s = new char[strlen(x)+1];
strcpy (s,x);
. - add a destructor to take care of that as well:
String::~String() { delete[] s; }
. - consider having your constructor receive a
const char *
(since you're not changing it). - consider using
toupper(ch)
instead ofch - 'a' + 'A'
. While your formula works for ASCII, I don't believe it's guaranteed by the standard. cout
stuff should be handled by the class rather then code outside of it (this will be mandatory once you makes
private.- consider having a no-argument constructor so that string arrays will work okay.
String literals are constant (you're exploiting a deprecated automatic conversion to char *
), and you're trying to modify one inside your class, which is undefined behavior.
In practice, the access violation happens because newer versions of VC++ put string literals in a section of the executable which is mapped in memory as read-only (which is definitely a good thing), and any attempt to write it results (correctly) in an access violation.
Solution: copy the string passed to the constructor (which, by the way, should take a const char *
) in a buffer local to your class, probably dynamically allocated. In this last case, if you don't want to implement a copy constructor and an assignment operator, make them private thus avoiding that the default ones are executed, otherwise you'll get troubles (double free
s and other nasty stuff) if you create copies of a String object.
Better solution: in real projects, don't reinvent the wheel and use a good pre-made string class like std::string
/CString
/wxString
/whatever the framework you're using provides you.
String::String(char*x)
{
s = x;
}
You shouldn't copy string literals address just like above. Behavior is undefined. you need to allocate memory and copy it.
size_t len = strlen(x);
s = new char[len+1];
strcpy(s,x);
Make sure to delete it in destructor of your String class.
You tried to assign to a string literal. They are not char*, they are const char*. Attempting to modify a string literal is undefined behaviour.
"test" is a const string, you cannot write to it. Instead of s = x; try doing strcpy, so that s will have a non-const copy of x, rather than the const original.
You cannot modify "test" string by accessing with [].
The error is s[i] = something.
Infact, char* is only a pointer to an IMMUTABLE string. In the constructor you must allocate space internally for handle "test" string literal and then you can modify single character accessing with [] operator.
Example to solve (with basic copyng):
String::String(char *original)
{
size_t len = strlen(original) + 1;
s = new char[len];
for ( size_t i = 0; i < len; ++i )
{
s[i] = original[i];
}
}
精彩评论