C++字符串和指针操作
C++ String and Pointers Manipulation
假设我在C++中有这样的数据结构:
struct Stash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
// Functions!
void initialize(int size);
void cleanup();
int add(const void* element);
void* fetch(int index);
int count();
void inflate(int increase);
};///:~
void Stash::initialize(int sz) {
size = sz;
quantity = 0;
storage = 0;
next = 0;
}
int Stash::add(const void* element) {
if(next >= quantity) // Enough space left?
inflate(increment);
// Copy element into storage,
// starting at next empty space:
int startBytes = next * size;
unsigned char* e = (unsigned char*)element;
for(int i = 0; i < size; i++){
storage[(startBytes + i)] = e[i];
}
next++;
return(next - 1); // Index number
}
void* Stash::fetch(int index) {
// Check index boundaries:
assert(0 <= index);
if(index >= next)
return 0; // To indicate the end
// Produce pointer to desired element:
int value = (index*size);
return &(storage[value]);
}
int Stash::count() {
return next; // Number of elements in CStash
}
void Stash::inflate(int increase) {
assert(increase > 0);
int newQuantity = quantity + increase;
int newBytes = newQuantity * size;
int oldBytes = quantity * size;
unsigned char* b = new unsigned char[newBytes];
for(int i = 0; i < oldBytes; i++)
b[i] = storage[i]; // Copy old to new
delete []storage; // Old storage
storage = b; // Point to new memory
quantity = newQuantity;
}
void Stash::cleanup() {
if(storage != 0) {
cout << "freeing storage" << endl;
delete []storage;
}
} ///:~
假设现在我使用数据结构以这种方式记忆字符串:
int main(){
Stash* st1 = new Stash;
st1->initialize(sizeof(string));
string s1 = "This is a GOOD morning";
st1->add(&s1);
string s2 = "This is a BAD morning";
st1->add(&s2);
string* s3;
s3 = static_cast<string*> (st1->fetch(0));
cout << *s3 << endl;
string* s3;
s3 = static_cast<string*> (st1->fetch(1));
cout << *s3 << endl;
st1->cleanup();
delete st1;
return 0;
}
它有效!!!这是输出:
This is a GOOD morning
This is a BAD morning
但在另一方面:
int main(){
Stash* st1 = new Stash;
st1->initialize(sizeof(string));
string s1 = "This is a GOOD morning";
st1->add(&s1);
s1 = "This is a BAD morning";
st1->add(&s1);
string* s3;
s3 = static_cast<string*> (st1->fetch(0));
cout << *s3 << endl;
string* s4;
s4 = static_cast<string*> (st1->fetch(1));
cout << *s4 << endl;
st1->cleanup();
delete st1;
return 0;
}
它不起作用。这是输出:
This is a BAD morning
This is a BAD morning
那么,当我尝试使用相同的引用时,机器中发生了什么?我尝试过其他数据类型,效果很好。
s1的第一次使用调用构造函数:
string s1 = "This is a GOOD morning";
然后将s1的地址添加到Stash中。接下来,您为s1分配一个新值:
s1 = "This is a BAD morning";
这不会创建新的字符串,而是调用赋值运算符,该运算符用新值替换相同的string
对象。然后保存s1地址的另一个副本:
st1->add(&s1);
如果您查看st1
中的数据,您将看到同一指针的两个副本,都指向s1。这是意料之中的事。在第一种情况下,您将存储指向两个不同对象的指针,这两个对象包含不同的值。
您的代码复制组成std::string
容器的字节(而不是字符串数据中的字符)。这可能包括指向字符串数据的指针,以及大小和容量。
当您写入s1 = "stuff"
时,std::string
会在内部分配新内存,因此它以前的内部指针现在无效。
然后从数据结构中检索以前的内部指针并尝试使用它,从而导致未定义的行为。
如果要保存字符串中的字符,则需要添加s1.c_str()
而不是&s1
。
如果您的意图是存储任何对象的副本,那么您需要调用副本构造函数来创建副本;不要像现在这样按位复制。如果您的目的是存储对象而不留下原始对象,您还可以调用移动构造函数或移赋值运算符。
在第二种方法中,您使用了s1的地址来存储在堆栈中。并且您没有复制堆栈中的内容,所以当您将s1更改为具有不同的内容时,早期的内容也会更改,因为您实际上是推送了指针,而不是内容的副本。例如,如果您执行以下操作(将内容复制到一个新的字符串中用于推送),这将起作用:
string s1 = "This is a GOOD morning";
st1->add(new string(s1));
s1 = "This is a BAD morning";
st1->add(new string(s1));
- 迭代器的指针操作问题
- 我试图了解在异或操作后指针变量正在更改
- 通过浮点指针操作字节向量
- 使用 XOR 操作仅使用 2 个指针反转链表
- 为什么指针在由后增量比较器操作时行为不同?
- 指针 OOP 操作
- C++数组指针上的删除操作
- 如何有效地使用 std::async 对指针数组执行操作
- 为什么在执行增量操作之前分配指针值
- 是否可以使用C++函数指针,如 C# 的操作?
- 共享指针,C 版本的原子操作
- 普通指针,连同通常的操作 & 和 *,是 monad 吗?
- 双指针 **src 和操作 (*(*src)++ = reg_offset)
- 调用向量内的函数指针不执行任何操作
- 调用 vector.erase() 函数时指针操作无效错误
- 即使在单线程程序中,共享指针是否在引用计数中使用原子操作
- C 弦乐操作用指针,中间为空
- 尝试仅通过操作指针对链表进行排序
- 在类内部操作指针
- 仅通过操作指针交换链表中的相邻节点