從函數返回C字符串




(8)

我想從函數返回一個C字符串,但它不工作。 這是我的代碼。

char myFunction()
{
    return "My String";
}

主要我這樣稱呼它:

int main()
{
  printf("%s",myFunction());
}

我也為myFunction嘗試了其他一些方法,但他們不工作。 例如:

char myFunction()
{
  char array[] = "my string";
  return array;
}

注意:我不允許使用指針!

關於這個問題的小背景:有找出它是哪個月份的函數; 如果它的1則返回1月等等。

所以當它打印時,它就是這樣做的。 printf("Month: %s",calculateMonth(month)); 。 現在的問題是如何從calculateMonth函數返回該字符串。


AC字符串被定義為指向字符數組的指針。

如果你不能有指針,根據定義你不能有字符串。


char只是一個單字節字符。 它不能存儲字符串,也不是一個指針(你顯然不能這樣做)。 因此,如果不使用指針,那麼你不能解決問題(其中char[]是語法糖)。


你的函數原型聲明你的函數將返回一個字符。 因此,你不能在你的函數中返回一個字符串。


你的函數簽名需要是:

const char * myFunction()
{
    return "My String";
}

編輯:

背景:

這篇文章已經有好幾年了,從來沒有想過它會被投票,因為它對於C&C ++來說非常重要。 儘管如此,還是應該多一點討論。

在C(&C ++)中,一個字符串只是一個以零字節結尾的字節數組,因此術語“字符串零”用於表示這種特殊的字符串風格。 還有其他種類的字符串,但在C(&C ++)中,這種風格本身就是由語言本身所理解的。 其他語言(Java,Pascal等)使用不同的方法來理解“我的字符串”。

如果您曾經使用Windows API(使用C ++),您會看到相當有規律的函數參數,如:“LPCSTR lpszName”。 'sz'部分錶示'string-zero'的概念:帶有空(/零)終止符的字節數組。

澄清:

為了這個'介紹',我交替使用'字節'和'字符'這個詞,因為這樣更容易學習。 請注意,還有其他方法(寬字符和多字節字符系統 - mbcs)用於處理國際字符。 UTF-8是一個mbcs的例子。 為了介紹,我悄悄地'跳過'所有這一切。

記憶:

這意味著像“我的字符串”這樣的字符串實際上使用9 + 1(= 10!)個字節。 這對了解何時終於動態分配字符串非常重要。 所以,沒有這個“終止零”,你沒有一個字符串。 你有一系列的字符(也稱為緩衝區)掛在內存中。

數據的長壽:

這種方式的使用功能:

const char * myFunction()
{
    return "My String";
}
int main() 
{
    const char* szSomeString = myFunction(); // fraught with problems
    printf("%s", szSomeString);
}

......通常會給你帶來隨機的未處理的異常/段錯誤等,尤其是“在路上”。

簡而言之,雖然我的答案是正確的--10次中有9次,如果你這樣使用它,你會得到一個崩潰的程序,特別是如果你認為這樣做是'好的做法'。 簡而言之:通常不會。

例如,想像未來的某個時間,現在需要以某種方式操縱字符串。 一般來說,編碼人員會採取“簡單的路徑”和(嘗試)像這樣編寫代碼:

const char * myFunction(const char* name)
{
    char szBuffer[255];
    snprintf(szBuffer, sizeof(szBuffer), "Hi %s", name);
    return szBuffer;
}

也就是說,你的程序會崩潰,因為在調用printf()中的printf() ,編譯器(可能/不可能)已經釋放了szBuffer使用的內存。 (你的編譯器也應事先警告你這些問題)。

有兩種方法可以返回不會很容易出錯的字符串。

  1. 返回存在一段時間的緩衝區(靜態或動態分配)。 在C ++中,使用'helper classes'(例如std::string )來處理數據的壽命(這需要改變函數的返回值),或者
  2. 將緩衝區傳遞給用信息填充的函數。

請注意,如果不使用C中的指針,則不可能使用字符串。正如我所示,它們是同義詞。 即使在使用模板類的C ++中,背景中也總是會使用緩衝區(即指針)。

所以,為了更好地回答(現在修改的問題)。 (肯定會有各種可以提供的“其他答案”)。

更安全的答案:

例如1.使用靜態分配的字符串:

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"
}

這裡的'靜態'是什麼(許多程序員不喜歡這種類型的'分配')是字符串被放入程序的數據段。 也就是說,它是永久分配的。

如果你轉向C ++,你會使用類似的策略:

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;
    }   
}

......但如果你正在編寫自己使用的代碼(而不是與其他人共享庫的一部分),那麼使用助手類比如std::string會更容易。

例如2.使用呼叫者定義的緩衝區:

這是傳遞字符串的更“不錯的方式”。 返回的數據不受主叫方操縱。 也就是說,例如,1可能很容易被主叫方濫用,並將您暴露給應用程序故障。 這樣,它更安全(儘管使用更多的代碼行):

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"
}

第二種方法更好的原因有很多,特別是如果你正在編寫一個供其他人使用的庫(你不需要鎖定特定的分配/釋放方案,第三方不能破壞你的代碼,你不需要鏈接到特定的內存管理庫),但是像所有的代碼一樣,它取決於你最喜歡什麼。 出於這個原因,大多數人選擇例如1,直到他們被燒得太多,以至於他們不再那麼寫了;)

免責聲明:

幾年前我退休了,現在我的C有點生疏。 這個演示代碼應該全部用C編譯(對於任何C ++編譯器來說都可以)。


你的問題是函數的返回類型 - 它必須是:

char *myFunction()

...然後您的原始配方將工作。

請注意,如果沒有涉及指針的C字符串, 則不能使用C字符串。

另外:打開你的編譯器警告,它應該已經警告你關於將char *轉換為char而沒有顯式強制轉換的返回行。


在你的代碼中,你試圖返回一個String (在C中,它只是以空字符結尾的字符數組),但是函數的返回類型是char ,它會給你帶來麻煩。 相反,你應該這樣寫:

const char* myFunction()
{

    return "My String";

}

並且用const限定你的類型總是好的,同時把C中的文字分配給指針,因為C中的文字是不可修改的。


如果你真的不能使用指針,可以這樣做:

char get_string_char(int index)
{
    static char array[] = "my string";
    return array[index];
}

int main()
{
    for (int i = 0; i < 9; ++i)
        printf("%c", get_string_char(i));
    printf("\n");
    return 0;
}

幻數9很糟糕,這不是一個好的編程例子。 但你明白了。 請注意,指針和數組是相同的東西(有點),所以這有點作弊。

希望這可以幫助!


或者這個怎麼樣:

void print_month(int month)
{
    switch (month)
    {
        case 0:
            printf("january");
            break;
        case 1:
            printf("february");
            break;
        ...etc...
    }
}

並在你計算的其他地方的月份中調用它。

問候,

Sebastiaan






c  

c