2010-06-16 21 views
5

Có thể tạo một chuỗi ký tự có thể sửa đổi trong C++ không? Ví dụ:Tạo chuỗi có thể sửa đổi theo nghĩa đen trong C++

char* foo[] = { 
    "foo", 
    "foo" 
}; 
char* afoo = foo[0]; 
afoo[2] = 'g'; // access violation 

Điều này tạo ra vi phạm truy cập vì "foo" được cấp phát trong bộ nhớ chỉ đọc (phần tôi tin). Có cách nào để buộc "foo" vào bộ nhớ ghi (phần .data)? Ngay cả thông qua một pragma sẽ được chấp nhận! (Visual Studio compiler)

Tôi biết tôi có thể làm strdup và một số thứ khác để giải quyết vấn đề, nhưng tôi muốn biết cụ thể nếu tôi có thể làm như tôi đã hỏi. :)

+1

Không, theo tiêu chuẩn sửa đổi một chuỗi chữ gợi lên hành vi không xác định. Bản thân dữ liệu là 'const', ngay cả khi bạn có con trỏ không phải là 'const'. Nếu bạn làm điều này bạn có nguy cơ gặp vấn đề từ chạy để chạy, hoặc khi bạn thay đổi hoặc thậm chí vá trình biên dịch của bạn. –

+0

Việc thay đổi chuỗi ** chữ ** sẽ không có ý nghĩa. Có lẽ nó rõ ràng hơn với int: làm thế nào để làm cho '5 = 7' biên dịch? – fredoverflow

+0

Anne, đây không phải là điều bạn nên làm, nhưng có thể thực hành, dựa vào tiêu chuẩn C++ nói. Tôi đã viết một bài báo giải thích cách làm điều này trong các hệ thống giống UNIX có giao diện bảo vệ bộ nhớ được tiếp xúc với các chương trình không gian người dùng, [kiểm tra nó ở đây] (http://lazarenko.me/2013/05/01/how-constant -is-a-constant /). –

Trả lời

1

Bạn có thể tạo một mảng đa chiều của chars:

#include <iostream> 

int main(int argc, char** argv) 
{ 
    char foo[][4] = { 
     "foo", 
     "bar" 
    }; 
    char* afoo = foo[0]; 
    afoo[2] = 'g'; 
    std::cout << afoo << std::endl; 
} 

cách gửi tiết để xác định các mảng:

char foo[][4] = { 
    {'f', 'o', 'o', '\0'}, 
    {'b', 'a', 'r', '\0'} 
}; 
+2

Bạn vẫn có thể sử dụng các chuỗi ký tự, bạn không phải chỉ định tất cả các ký tự là char literals. –

+0

@Noah: Cảm ơn bạn đã chỉ ra điều đó. –

+2

Ngoài ra, Anne nên ghi nhớ rằng nếu cô ấy làm theo cách này thì 4 phải là kích thước của chuỗi dài nhất +1. Sử dụng một lớp chuỗi thực sự là lựa chọn tốt hơn nhưng điều này là gần với những gì cô ấy dường như muốn như cô ấy sẽ nhận được. –

9

Vì đây là C++, câu trả lời "tốt nhất" là sử dụng một lớp chuỗi (std::string, QString, CString, v.v. tùy thuộc vào môi trường của bạn).

Để trả lời câu hỏi của bạn trực tiếp, bạn không được phép sửa đổi chuỗi ký tự. Tiêu chuẩn cho biết đây là hành vi không xác định. Bạn thực sự cần phải lặp lại các chuỗi một cách này hay cách khác, nếu không bạn đang viết không chính xác C + +.

+2

+1 cho 'std :: string', -1 cho các chuỗi không chuẩn. –

+1

@Mike Seymour: Khi ở Rome ... – Cogwheel

+2

Để xây dựng, nếu bạn đang sử dụng một khung có lớp chuỗi riêng, bạn sẽ làm cho cuộc sống của bạn trở nên khó khăn hơn bằng cách cố gắng phù hợp với 'std :: string' vào hỗn hợp. Do đó "tùy thuộc vào môi trường của bạn" – Cogwheel

2

Nếu bạn lưu chuỗi của mình trong một mảng, bạn có thể thay đổi chuỗi đó.

Không có cách nào để 'chính xác' ghi vào bộ nhớ chỉ đọc.

Bạn có thể, tất nhiên, ngừng sử dụng C-strings.

+0

Chính xác là chủ quan. Theo đúng những gì? Theo phần cứng, có một cách khá chính xác và đơn giản để làm điều này, xem xét không có những thứ như bộ nhớ chỉ đọc trong khá nhiều tất cả các phần cứng hàng hóa, thực sự. –

4

Tôi nghĩ gần nhất bạn có thể đến là để khởi tạo một đồng bằng char[] (không phải là một char * []) ​​với một chữ:

char foo[] = "foo"; 

Đó vẫn sẽ thực hiện một bản sao tại một số điểm mặc dù.

Cách duy nhất khác xung quanh đó là sử dụng các cuộc gọi cấp hệ thống để đánh dấu trang mà một chuỗi ký tự nằm ở dạng có thể ghi. Tại thời điểm đó bạn không thực sự nói về C hoặc C++, bạn đang thực sự nói về Windows (hoặc bất cứ hệ thống nào bạn đang chạy). Nó có thể có thể trên hầu hết các hệ thống (trừ khi dữ liệu thực sự trong ROM, có thể là trường hợp trên một hệ thống nhúng chẳng hạn), nhưng tôi chắc chắn không biết chi tiết.

Oh, và đừng quên rằng trong ví dụ của bạn:

char* foo[] = { 
    "foo", 
    "foo" 
}; 

Kể từ tiêu chuẩn (C99 6.4.5/6 "literals String") nói:

Đó là không xác định liệu các mảng này khác biệt với điều kiện các phần tử của chúng có các giá trị thích hợp.

Không chắc chắn về việc liệu 2 con trỏ trong mảng đó sẽ trỏ đến cùng một đối tượng hoặc riêng biệt. Gần như tất cả các trình biên dịch sẽ có những con trỏ trỏ đến cùng một đối tượng ở cùng một địa chỉ, nhưng chúng không phải và một số tình huống phức tạp hơn của các con trỏ tới chuỗi ký tự chuỗi có thể có trình biên dịch đến với 2 chuỗi giống hệt nhau.

Bạn thậm chí có thể có một kịch bản mà một chuỗi chữ tồn tại 'bên' khác:

char* p1 = "some string"; 
char* p2 = "string"; 

p2 cũng có thể được chỉ ở phần cuối đuôi của chuỗi được trỏ đến bởi p1.

Vì vậy, nếu bạn bắt đầu thay đổi chuỗi ký tự bằng một số hack bạn có thể thực hiện trên hệ thống, bạn có thể kết thúc việc sửa đổi một số chuỗi 'khác' một cách vô tình. Đó là một trong những điều mà hành vi không xác định có thể mang lại.

+0

cũng có 'char _foo [] =" foo "; char * foo = & _foo [0] ' –

1

Tôi sẽ không làm điều này. Vì vậy, tôi chỉ có thể cung cấp một tin xấu xấu xí hack bạn có thể thử: Nhận trang nơi chữ thường xuyên của bạn cư trú và không bảo vệ trang đó. Xem hàm VirtualProtect() cho Win32. Tuy nhiên, ngay cả khi điều này làm việc, nó sẽ không đảm bảo hành vi chính xác tất cả các thời gian. Tốt hơn là đừng làm thế.

-3

Yes.

(char[]){"foo"} 
+2

Điều này gợi lên hành vi không xác định. –

Các vấn đề liên quan