chữ ký chức năng của bạn cần phải được:
const char * myFunction()
{
return "My String";
}
Edit:
Bối cảnh:
Đó là năm kể từ khi bài này & không bao giờ nghĩ rằng nó sẽ được bầu lên, bởi vì nó rất cơ bản đối với C & C++. Tuy nhiên, cần thảo luận thêm một chút.
Trong C (& C++ cho vấn đề đó), một chuỗi chỉ là một mảng byte được kết thúc bằng byte không - do đó thuật ngữ "chuỗi-số không" được sử dụng để thể hiện hương vị đặc biệt của chuỗi. Có các loại dây khác, nhưng trong C (& C++), hương vị này vốn đã được hiểu bởi chính ngôn ngữ đó. Các ngôn ngữ khác (Java, Pascal, vv) sử dụng các phương pháp khác nhau để hiểu "chuỗi của tôi".
Nếu bạn đã từng sử dụng API Windows (trong C++), bạn sẽ thấy các thông số chức năng khá thường xuyên như: "LPCSTR lpszName". Phần 'sz' đại diện cho khái niệm 'chuỗi-số không' này: một mảng các byte có một terminator null (/ zero).
Làm rõ:
Vì mục đích của việc này 'giới thiệu', tôi sử dụng từ 'byte' và 'nhân vật' thay thế cho nhau, bởi vì nó dễ dàng hơn để học hỏi theo cách này. Lưu ý rằng có các phương thức khác (ký tự rộng và các hệ thống ký tự nhiều byte - mbcs) được sử dụng để đối phó với các ký tự quốc tế. UTF-8 là một ví dụ về một mbcs. Vì mục đích giới thiệu, tôi lặng lẽ 'bỏ qua' tất cả những điều này.
Memory:
Điều này có nghĩa là một chuỗi như "chuỗi của tôi" thực sự sử dụng 9 + 1 (= 10) byte. Điều này rất quan trọng để biết khi nào bạn cuối cùng cũng có được xung quanh để phân bổ chuỗi động. Vì vậy, nếu không có 'chấm dứt bằng không', bạn không có chuỗi. Bạn có một mảng ký tự (còn được gọi là bộ đệm) treo xung quanh trong bộ nhớ.
Tuổi thọ của dữ liệu:
Việc sử dụng các chức năng như sau:
const char * myFunction()
{
return "My String";
}
int main()
{
const char* szSomeString = myFunction(); // fraught with problems
printf("%s", szSomeString);
}
... nói chung sẽ đất bạn với ngẫu nhiên unhandled-ngoại lệ/lỗi phân khúc và những thứ tương tự, đặc biệt là ' xuống đường '.
Tóm lại, mặc dù câu trả lời của tôi là đúng - 9 lần trong số 10 bạn sẽ kết thúc với một chương trình bị treo nếu bạn sử dụng theo cách đó, đặc biệt nếu bạn cho rằng đó là 'thực hành tốt' . Tóm lại: Nói chung là không.
Ví dụ: hãy tưởng tượng một thời gian trong tương lai, chuỗi hiện cần được thao tác theo một cách nào đó. Nói chung, một coder sẽ 'đi theo con đường dễ dàng' và (cố gắng) viết mã như thế này:
const char * myFunction(const char* name)
{
char szBuffer[255];
snprintf(szBuffer, sizeof(szBuffer), "Hi %s", name);
return szBuffer;
}
Đó là, chương trình của bạn sẽ sụp đổ vì trình biên dịch (có thể/không) đã phát hành bộ nhớ được sử dụng bởi szBuffer
vào thời điểm printf()
trong số main()
được gọi. (Trình biên dịch của bạn cũng nên cảnh báo bạn về những vấn đề như vậy trước).
Có hai cách để trả lại các chuỗi không bị chặn dễ dàng.
- bộ đệm trả về (tĩnh hoặc được phân bổ động) tồn tại trong một thời gian. Trong C++ sử dụng 'lớp trợ giúp' (ví dụ:
std::string
) để xử lý tuổi thọ của dữ liệu (yêu cầu thay đổi giá trị trả về của hàm) hoặc
- chuyển bộ đệm đến hàm được điền thông tin.
Lưu ý rằng không thể sử dụng chuỗi mà không sử dụng con trỏ trong C. Như tôi đã chỉ ra, chúng đồng nghĩa. Ngay cả trong C++ với các lớp mẫu, luôn có bộ đệm (tức là con trỏ) đang được sử dụng trong nền.
Vì vậy, để trả lời tốt hơn (câu hỏi đã được sửa đổi). (chắc chắn có một loạt các 'câu trả lời khác' có thể được cung cấp).
Đáp Safer:
ví dụ 1. sử dụng chuỗi tĩnh được phân bổ:
const char* calculateMonth(int month)
{
static char* months[] = {"Jan", "Feb", "Mar" .... };
static char badFood[] = "Unknown";
if (month<1 || month>12)
return badFood; // choose whatever is appropriate for bad input. Crashing is never appropriate however.
else
return months[month-1];
}
int main()
{
printf("%s", calculateMonth(2)); // prints "Feb"
}
gì 'tĩnh' không ở đây (nhiều lập trình viên không thích kiểu này 'phân bổ) là ở chỗ các chuỗi được đưa vào phân đoạn dữ liệu của chương trình. Đó là, nó được phân bổ vĩnh viễn.
Nếu bạn di chuyển qua C++ bạn sẽ sử dụng chiến lược tương tự:
class Foo
{
char _someData[12];
public:
const char* someFunction() const
{ // the final 'const' is to let the compiler know that nothing is changed in the class when this function is called.
return _someData;
}
}
... nhưng nó có thể dễ dàng hơn để sử dụng các lớp helper như std::string
, nếu bạn đang viết mã cho riêng bạn sử dụng (và không phải là một phần của thư viện được chia sẻ với người khác).
ví dụ: 2. sử dụng bộ đệm được người gọi xác định:
Đây là cách 'đánh lừa bằng chứng' để truyền các chuỗi xung quanh. Dữ liệu được trả về không bị thao tác bởi bên gọi điện. Đó là, ví dụ 1 có thể dễ dàng bị lạm dụng bởi một bên gọi điện thoại và cho bạn thấy lỗi ứng dụng. Bằng cách này, nó là an toàn hơn nhiều (mặc dù sử dụng nhiều dòng mã):
void calculateMonth(int month, char* pszMonth, int buffersize)
{
const char* months[] = {"Jan", "Feb", "Mar" .... }; // allocated dynamically during the function call. (Can be inefficient with a bad compiler)
if (!pszMonth || buffersize<1)
return; // bad input. Let junk deal with junk data.
if (month<1 || month>12)
{
*pszMonth = '\0'; // return an 'empty' string
// OR: strncpy(pszMonth, "Bad Month", buffersize-1);
}
else
{
strncpy(pszMonth, months[month-1], buffersize-1);
}
pszMonth[buffersize-1] = '\0'; // ensure a valid terminating zero! Many people forget this!
}
int main()
{
char month[16]; // 16 bytes allocated here on the stack.
calculateMonth(3, month, sizeof(month));
printf("%s", month); // prints "Mar"
}
Có rất nhiều lý do tại sao phương pháp thứ 2 là tốt hơn, đặc biệt là nếu bạn đang viết một thư viện để được sử dụng bởi những người khác (bạn don 't cần phải khóa vào một giao thức phân bổ/deallocation cụ thể, bên thứ ba không thể phá vỡ mã của bạn, bạn không cần phải liên kết đến một thư viện quản lý bộ nhớ cụ thể), nhưng giống như tất cả các mã, nó thuộc vào bạn về những gì bạn thích tốt. Vì lý do đó, hầu hết mọi người lựa chọn ví dụ 1 cho đến khi họ đã bị đốt cháy rất nhiều lần rằng họ từ chối để viết nó theo cách đó nữa;)
từ chối trách nhiệm:
tôi nghỉ hưu vài năm trở lại và C của tôi bây giờ hơi bị gỉ. Mã trình diễn này nên biên dịch hoàn toàn với C (mặc dù vậy cũng không sao đối với bất kỳ trình biên dịch C++ nào).
Thật không may bạn * cần * con trỏ trong trường hợp này. –
Tại sao bạn không thể sử dụng con trỏ? –
(bạn cần phải trả lại một int trong chính bằng cách này) – user224579