2012-05-27 29 views
5

Tôi thiếu gì ở đây? Điều đó khiến tôi phát điên!C++: Tại sao tôi không thể in một ký tự const * với sprintf?

Tôi có một hàm trả về một const char *

const char* Notation() const 
{ 
    char s[10]; 
    int x=5; 
    sprintf(s, "%d", x); 
    return s; 
} 

Bây giờ trong một phần khác của mã tôi đang làm điều này:

..... 
..... 
char str[50];  
sprintf(str, "%s", Notation()); 
..... 
..... 

nhưng str vẫn không thay đổi.

Nếu thay vào đó tôi làm điều này:

..... 
..... 
char str[50]; 
str[0]=0; 
strcat(str, Notation()); 
..... 
..... 

str được thiết lập một cách chính xác.

Tôi tự hỏi tại sao sprintf không hoạt động như mong đợi ...

+0

Có thể một ý tưởng là thay đổi hàm thành: void Ký hiệu (char * buffer) const và làm việc trên bộ đệm char do người gọi cung cấp. – Wartin

+0

Tại sao lại là downvote? Câu hỏi là rõ ràng, một mẫu "làm việc" đã được đưa ra, trong đó cho thấy nỗ lực, và mẫu vấn đề thực tế được đưa ra. – chris

Trả lời

9

Bạn đang cố gắng để trả lại một mảng cấp phát trên stack và hành vi của nó là không xác định.

const char* Notation() const 
{ 
    char s[10]; 
    int x=5; 
    sprintf(s, "%d", x); 
    return s; 
} 

tại đây s sẽ không có mặt sau khi bạn quay trở lại từ hàm Notation(). Nếu bạn không quan tâm đến sự an toàn của luồng, bạn có thể làm cho s tĩnh.

const char* Notation() const 
{ 
    static char s[10]; 
    .... 
+0

Tôi nghĩ rằng bộ đệm được cấp phát lúc biên dịch và vẫn ở đó trong suốt thời gian tồn tại của ứng dụng. Nếu điều này không đúng, thì điều này không có nghĩa là mọi hàm trả về một const char không toàn cục * đều sai? (và nguy hiểm) – Wartin

+1

Bất kỳ chức năng nào trả về tự động const char * đều nguy hiểm. Có rất nhiều cách khác để trả về bộ đệm - ví dụ như bộ đệm tĩnh và cũng mới được cấp phát bằng cách sử dụng malloc. tuy nhiên nếu bạn trả về các bộ đệm malloc'd bạn đã quản lý dọn dẹp đúng cách. – hawk

+0

@Wartin: Tôi nghĩ bạn đang nghĩ về chuỗi ký tự. Nếu, ví dụ, bạn nói: 'return 'foobar"; '- Điều đó sẽ an toàn, vì chuỗi" foobar "kéo dài suốt vòng đời của ứng dụng. –

5

Trong cả hai trường hợp, nó gọi hành vi không xác định, như Notation() trả về một mảng cục bộ bị hủy khi trả lại. Bạn đang không may mắn mà nó hoạt động trong một trường hợp, làm cho bạn cảm thấy rằng điều đó là chính xác.

Các giải pháp là sử dụng std::string như:

std::string Notation() const 
{ 
    char s[10]; 
    int x=5; 
    sprintf(s, "%d", x); 
    return s; //it is okay now, s gets converted into std::string 
} 

Hoặc sử dụng C++ dòng như:

std::string Notation() const 
{ 
    int x=5; 
    std::ostringstream oss; 
    oss << x; 
    return oss.str(); 
} 

và sau đó:

char str[50];  
sprintf(str, "%s", Notation().c_str()); 

Lợi ích (và vẻ đẹp) của std::ostringstream (và std::string) là bạn không cần phải biết kích thước của đầu ra i n trước, có nghĩa là bạn không phải sử dụng số ma thuật như 10 trong khai báo mảng char s[10]. Những lớp học này an toàn theo nghĩa đó.

1

char s[10] trong Notation được đặt trên ngăn xếp để nó bị hủy sau khi thoát khỏi hàm Notation. Các biến số này được gọi là automatic.Bạn cần phải lưu chuỗi của bạn trong đống sử dụng new:

char *s = new char[10]; 

Nhưng bạn có để giải phóng bộ nhớ này bằng tay:

char str[50]; 
const char *nt = Notation(); 
sprintf(str, "%s", nt); 
printf("%s", str); 
delete[] nt; 

Nếu bạn thực sự sử dụng C++ sau đó sử dụng built-in string lớp như Nawaz gợi ý. Nếu bạn bằng cách nào đó bị hạn chế với con trỏ thô sau đó phân bổ bộ đệm bên ngoài Notation và chuyển nó thành tham số destanation như trong sprintf hoặc strcat.

+1

Trong khi đó sẽ giải quyết vấn đề, đó là một ý tưởng khủng khiếp. Nếu anh ta cố gắng sử dụng chức năng như bây giờ, nó sẽ là một rò rỉ bộ nhớ được bảo đảm. –

+0

Vâng, đúng vậy. Vì câu hỏi là về C++ thì 'string' là lựa chọn tốt nhất. – Kirill

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