2011-08-25 56 views
10

numCheck là số từ 1-1000. Mã này cho tôi một segfault chỉ khi tôi thu thập các kết quả của sprintf trong charcheck. Nếu tôi chỉ đơn giản là sử dụng sprintf mà không sử dụng kết quả, tôi không nhận được một lỗi seg. Điều gì đang xảy ra ở đây?Lỗi phân đoạn Sprintf

char * numString; 
int charcheck = sprintf(numString, "%d", numCheck); 

Trả lời

7

Bạn cần cung cấp bộ nhớ riêng cho sprintf. Ngoài ra, không sử dụng sprintf, nhưng thay vì snprintf:

char buf[1000] = {0}; 

snprintf(buf, 999, ....); 

Hoặc bạn có thể cấp phát bộ nhớ động:

char * buf = new char[BUFSIZE]; 
snprintf(buf, BUFSIZE-1, ...); 
/* ... */ 
delete[] buf; 
+0

Chính xác vì sao nó hoạt động khi tôi không thu thập kết quả? – syl

+0

Hành vi không xác định. Đôi khi hành vi không xác định hoạt động chính xác như bạn mong đợi, điều này được cho là trường hợp xấu nhất. –

+1

Tại sao bạn đề nghị 'snprintf' trên 'sprintf'? – Kevin

1

Đối số đầu tiên để sprintf phải trỏ đến một bộ đệm hợp lệ. Bạn có một char* nhưng nó chỉ vào thùng rác.

Thay đổi mã của bạn để:

char numString[80] = { }; 
int charcheck = sprintf(numString, "%d", numCheck); 

Vì vậy mà numString thực sự chỉ đến một bộ đệm hợp lệ (80 ký tự trong ví dụ này, tất cả các yếu tố trong số đó được khởi tạo vào 0).

Nó cũng sẽ là tốt để sử dụng snprintf để bạn có thể vượt qua kích thước của bộ đệm của bạn với nó, mà sẽ giúp ngăn chặn lỗi tràn bộ đệm:

const int bufsize = 80; 
char numString[bufsize] = { }; 
int charcheck = snprintf(numString, bufsize - 1, "%d", numCheck); 

Chú ý rằng bạn trừ đi một từ kích thước bộ đệm mà bạn vượt qua đến snprintf vì bạn không muốn nó sử dụng vị trí cuối cùng mà bạn muốn đảm bảo là NULL để biểu thị phần cuối của chuỗi.

+0

Có cách nào tôi có thể tìm ra kích thước của số nguyên mà tôi truyền vào các ký tự sao cho tôi có thể phân bổ số lượng không gian chính xác thay vì sử dụng một giá trị tùy ý như 80? – syl

+0

@user có lẽ sẽ hiệu quả hơn khi chỉ phân bổ không gian thừa (bạn có thể tìm ra số ký tự tối đa một số có thể là loại bạn đang lưu trữ) vì tính toán nó sẽ yêu cầu một chuỗi 'if's. Bạn chỉ cần tính số lớn nhất số của bạn nhỏ hơn (ví dụ: nếu số đó nhỏ hơn 10 (nhưng luôn luôn '> 0', hãy nhớ bạn) đó là 1 chữ số, nếu nó nhỏ hơn 100 thì có 2 chữ số, v.v ...). Nhưng phân bổ không gian trên ngăn xếp đòi hỏi thời gian không đổi (và một hằng số rất nhỏ ở đó) miễn là bạn không làm điều gì đó như 'char numString [9999999999999]' bạn nên ổn –

0

Bạn cần phải phân bổ không gian cho kết quả như

char numString[50]; 
int charcheck = sprintf(numString, "%d", numCheck); 

Trong trường hợp của bạn các hoạt động interal của sprintf đang cố gắng tham khảo NULL là giá trị mặc định cho một con trỏ trong trường hợp của bạn.

1

Con trỏ được cung cấp làm tham số đầu tiên là sprintf được dự kiến ​​sẽ trỏ tới vị trí bộ nhớ trong đó sprintf sẽ ghi chuỗi đã định dạng.

Trong trường hợp này, bạn không khởi tạo numString để trỏ đến một số bộ nhớ bạn đã cấp cho chuỗi được định dạng. Kể từ numString không được khởi tạo, nó có thể trỏ đến bất kỳ đâu và trong trường hợp của bạn, cố gắng ghi đầu ra đã định dạng đến vị trí đó dẫn đến lỗi phân đoạn.

0

Điều đơn giản nhất để làm là sử dụng một mảng như trên, ví dụ,

char numString[80] = { }; 

đề xuất bởi Seth, Chúa Giêsu và Kerrek.

Tôi nghĩ câu trả lời cuối cùng từ sth là một lời giải thích tốt: "tham số đầu tiên cho sprintf được dự kiến ​​sẽ trỏ đến vị trí bộ nhớ nơi sprintf nên viết chuỗi định dạng." Vì vậy, ngoài việc sử dụng một loạt các nhân vật, điều này sẽ buộc các phân bổ bộ nhớ cho chuỗi, bạn cũng có thể sử dụng này:

char *numstring = (char*) malloc(80); 

này nên để cho bạn một cách rõ ràng giải phóng bộ nhớ cấp phát khi nó không còn là cần thiết.