Từ 1 tới 3 trên tổng số 3 kết quả

Đề tài: thắc mắc với lệnh sprintf khi muốn

  1. #1
    Ngày gia nhập
    06 2018
    Bài viết
    0

    Unhappy thắc mắc với lệnh sprintf khi muốn

    đây là code của em

    ý tưởng: chuyển đổi số thực sang string trong trường hợp nó ngắn nhất (1,1) hoặc rất dài (cỡ chục chữ số)
    chuyển đổi để tiện ghi thông tin một object ra file hoặc in lên màn hình, khỏi mất công viết lại ý mà
    kích thước string kết quả chính là tham số size, ví dụ pi=3,1415926... muốn cắt phần thập phân cho gọn đi thì chỉ cần đặt size ngắn lại là thành 3,14

    Code:
    //đã include thư viện
    
    string realnum_toString(double real, int size)
    {
    	char *temp = new char[size];	//cấp phát chuỗi tạm trên heap
    	sprintf(temp, "%f", real);	// convert và nhét từng chữ số real vào mảng tạm
    	string result(temp);
     	delete[] temp;	//xóa mảng tạm đi sau khi hết giá trị lợi dụng
    	temp = NULL;
    
    	for (int i = result.size(); i>size; i--)
    		result.pop_back();	// cắt gọn phần thập phân, thông cảm em chưa nghĩ ra thuật toán làm tròn hihi =))
    
    	return result;
    }
    lẽ thường tình khi cấp phát động: cấp phát dùng xong phải delete;
    nhưng khi chạy, đoạn code bị lỗi ở lệnh delete, không biết tại văng exception hay lỗi gì nữa... đành bỏ delete đi

    nếu em ném đoạn code này vào project lớn, sử dụng lại vài trăm, vài nghìn lần thì hết cmn heap

    các anh chị có kinh nghiệm với lệnh này cho em cái giải đáp với ạ ! cảm ơn nhiều

  2. #2
    Ngày gia nhập
    06 2018
    Bài viết
    0

    mình đã ngồi mò cả ngày nay vẫn không fix đc
    cần lắm vừa fix đc vừa muốn hiểu đc vì sao nó lại như vậy

    ai giúp mình với !!!!

  3. #3
    Ngày gia nhập
    02 2014
    Nơi ở
    TP.HCM
    Bài viết
    843

    Vấn đề nằm ở chỗ chúng ta chưa xác định được chiều dài cần thiết cho lệnh sprintf. Tuy bạn cấp phát theo biến size nhưng không có gì bảo đảm lệnh sprintf chỉ đọc vào kích thước đó, nó sẽ ghi tràn qua vùng nhớ đã cấp phát (tức * temp). Khi tạo chuỗi mới result(temp);, lệnh này đã truy xuất vào vùng nhớ được ghi tràn trong temp, và khi xóa trình Debug phát hiện ra không hợp lệ nên văng lỗi.

    Để giải quyết ta có 2 cách, cách nào cũng phải tăng kích thước cấp phát lên một số lớn (tùy thuộc trên máy và TBD - tùy thuộc phiên bản sprintf nhưng chắc chắn nó khó vượt qua 64 Bytes).

    1. Cấp phát động char *temp = new char[64];, các dòng khác để nguyên (tôi không ban vòng for của bạn)
    2. Cấpp phát tĩnh char temp[64];, không cần xóa và đặt lại NULL.

    C++ Code:
    1. std::string realnum_toString(double real, int size)
    2. {
    3.     char *temp = new char[64];  //cấp phát chuỗi tạm trên heap
    4.     sprintf(temp, "%f", real);  // convert và nhét từng chữ số real vào mảng tạm
    5.     std::string result(temp);
    6.     delete[] temp;  //xóa mảng tạm đi sau khi hết giá trị lợi dụng
    7.     temp = NULL;
    8.  
    9.     for (int i = result.size(); i>size; i--)
    10.         result.pop_back();  // cắt gọn phần thập phân, thông cảm em chưa nghĩ ra thuật toán làm tròn hihi =))
    11.  
    12.     return result;
    13. }
    hoặc
    C++ Code:
    1. std::string realnum_toString(double real, int size)
    2. {
    3.     char temp[64];
    4.     sprintf(temp, "%f", real);  // convert và nhét từng chữ số real vào mảng tạm
    5.     std::string result(temp);
    6.  
    7.     for (int i = result.size(); i>size; i--)
    8.         result.pop_back();  // cắt gọn phần thập phân, thông cảm em chưa nghĩ ra thuật toán làm tròn hihi =))
    9.  
    10.     return result;
    11. }
    mã trên VS2015
    Visual C++ Code:
    1. #define _CRT_SECURE_NO_WARNINGS     // Trong VC++
    2. #include <iostream>
    3. #include <string>
    4. #include <stdio.h>
    5.  
    6. std::string realnum_toString(double real, int size)
    7. {
    8.     char temp[32];
    9.     sprintf(temp, "%f", real);  // convert và nhét từng chữ số real vào mảng tạm
    10.     std::string result(temp);
    11.  
    12.     for (int i = result.size(); i>size; i--)
    13.         result.pop_back();  // cắt gọn phần thập phân, thông cảm em chưa nghĩ ra thuật toán làm tròn hihi =))
    14.  
    15.     return result;
    16. }
    17.  
    18. double fRand(double fMin, double fMax)
    19. {
    20.     double f = (double)rand() / RAND_MAX;
    21.     return fMin + f * (fMax - fMin);
    22. }
    23.  
    24. int main()
    25. {
    26.     for (int i = 0; i < 100; i++)
    27.     {
    28.         double db = fRand(1.0, 10.0);
    29.         std::cout << realnum_toString(db, 5) << std::endl;
    30.     }
    31.     system("pause");    // Trong VC++
    32.        
    33.     return 0;
    34. }

    - - - Nội dung đã được cập nhật ngày 09-06-2018 lúc 08:46 AM - - -

    Giải quyết luôn cái vòng for giùm bạn.

    Visual C++ Code:
    1. #define _CRT_SECURE_NO_WARNINGS     // Trong VC++
    2. #include <iostream>
    3. #include <string>
    4. #include <stdio.h>
    5. #include <algorithm>
    6.  
    7. std::string realnum_toString(double real, int size)
    8. {
    9.     char    temp[64];
    10.     int     nReturn = sprintf(temp, "%f", real);
    11.     temp[std::min(size, nReturn)] = 0;
    12.     return std::string(temp);
    13.  
    14.     // Ngắn hơn nữa
    15.     // char temp[64];
    16.     // temp[std::min(size, sprintf(temp, "%f", real))] = 0;
    17.     // return std::string(temp);
    18.  
    19.     // Dễ hiểu hơn
    20.     // char temp[64];
    21.     // sprintf(temp, "%f", real);
    22.     // temp[size] = 0;
    23.     // return std::string(temp);
    24. }
    25.  
    26. double fRand(double fMin, double fMax)
    27. {
    28.     double f = (double)rand() / RAND_MAX;
    29.     return fMin + f * (fMax - fMin);
    30. }
    31.  
    32. int main()
    33. {
    34.     int     size = 4;   // Thay đổi tùy thuộc nhu cầu
    35.     for (int i = 0; i < 100; i++)
    36.     {
    37.         double db = fRand(1.0, 10.0);
    38.         std::cout << realnum_toString(db, size) << std::endl;
    39.     }
    40.     system("pause");    // Trong VC++
    41.        
    42.     return 0;
    43. }
    Đã được chỉnh sửa lần cuối bởi MHoang : 09-06-2018 lúc 08:58 AM.

Tags của đề tài này

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn