我的任務是在 C 中撰寫一個遞回函式,將任何字符的字串更改為全部大寫(不使用toupper()或任何其他函式)。
這是以前的代碼并嘗試解決問題:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* allCapStringRec(char str[])
{
if (str[0] == '\0' )
return 0;
if (str[0] >= 'a' && str[0] <= 'z')
str[0] = str[0] - 32;
return allCapStringRec(str 1);
}
代碼需要通過“測驗”成功編譯以檢查代碼 - 該函式自行作業但未完成該測驗。
測驗:
void Test3(char str[], char expected[], int dec)
{
char *result = allCapStringRec(str);
if (strcmp(result, expected) != 0)
printf("allCapStringRec => Your Output is %s, Expected: %s\n", result, expected);
}
int main()
{
Test3("123321", "123321", 4);
Test3("abBba", "ABBBA", 4);
Test3("ab$cd", "AB$CD", 4);
printf("done");
return 0;
}
我的輸出:
dupCapStringRec => Your Output is , Expected: 123321
抱歉所有的編輯,這是我的第一個問題。我需要幫助知道我做錯了什么:)
uj5u.com熱心網友回復:
這是遞回的可怕用途!這不礙事,所以我們如何修復這段代碼:
到目前為止,其他答案假設您可以更改Test3(),我假設您不能更改 - 這是其他人將測驗例程應用于您的代碼。如果是這樣,我看到兩種方法來處理它的呼叫:
char *result = allCapStringRec(str);
首先,假設我們可以用可寫字串編譯這段代碼——也就是說,我們可以修改傳入的任何allCapStringRec()字串。在這種情況下,回傳值只是一種方便,而不是遞回的一個組成部分:
char *allCapStringRec(char str[])
{
// assumes compiled with -fwritable-strings
if (str[0] == '\0') {
return str;
}
if (str[0] >= 'a' && str[0] <= 'z') {
str[0] -= ' ';
}
allCapStringRec(str 1);
return str; // convenience return, not strictly necessary
}
如果我們不能假設可寫字串,事情會變得更加復雜,因為我們必須創建一個新字串并回傳它。這里字串結果的回傳成為遞回的一部分:
char *allCapStringRec(char str[])
{
char *upper = calloc(strlen(str) 1, sizeof(char)); // calloc initializes to '\0'
if (str[0] == '\0') {
return upper;
} else if (str[0] >= 'a' && str[0] <= 'z') {
upper[0] = str[0] - ' ';
} else {
upper[0] = str[0];
}
char *tail = allCapStringRec(str 1);
(void) strcpy(upper 1, tail);
free(tail);
return upper;
}
如果這是假設的,那么Test3()就是有缺陷的,應該free(result)作為避免記憶體泄漏的最后一件事。但是使用calloc()并free()違反了您的“不使用 toupper() 或任何其他函式”的要求,因此無法解決不可寫字串的問題。
uj5u.com熱心網友回復:
您的代碼是錯誤的,但這并不是完全失敗。
這需要改變:
- 不要讓
allCapStringRecreturn 成為一個毫無意義的指標,而是讓它成為一個void函式。 - 不要嘗試修改字串文字(它們無法修改),而是將字串文字復制到臨時緩沖區并在該緩沖區上進行轉換。有關字串文字的此問題的更多資訊。
評論中的更多解釋:
void allCapStringRec(char str[]) // make the function void
{
if (str[0] == '\0')
return; // don't return anything
if (str[0] >= 'a' && str[0] <= 'z')
str[0] = str[0] - 32;
allCapStringRec(str 1); // don't return anything
}
void Test3(char str[], char expected[], int dec)
{
char testbuffer[100]; // temporary buffer that can be modified
strcpy(testbuffer, str); // copy source to temp buffer
allCapStringRec(testbuffer); // convert string in temp buffer
if (strcmp(testbuffer, expected) != 0) // compare converted testbuffer with expected
printf("allCapStringRec => Your Output is %s, Expected: %s\n", testbuffer, expected);
}
uj5u.com熱心網友回復:
問題 1:您嘗試修改只讀字串文字。為什么寫入用字串文字初始化的“char *s”而不是“char s[]”時會出現分段錯誤?相反,您必須將可寫字串傳遞給函式,因為您打算就地更改字串。
問題2:if (str[0] >= 'a' && str[0] <= 'z') str[0] = str[0] - 32;不是真正的可移植代碼。
問題 3:為了遞回而遞回(現在我們有 3 個問題)。
您可以更高效、更便攜地實作此功能:
(這也可以很容易地修改以涵蓋語言環境:法語、西班牙語、德語等)
void str_toupper (char* str)
{
static const char LUT[127] =
{
['a'] = 'A',
['b'] = 'B',
['c'] = 'C',
['d'] = 'D',
['e'] = 'E',
/* you get the idea */
};
for(size_t i=0; str[i] != '\0'; i )
{
char converted = LUT[ str[i] ];
if(converted)
str[i] = converted;
}
}
用法:
char str[] = "Hello World!";
str_toupper(str);
這里的技巧是查找表將所有未使用的專案設定為零,并且在大寫轉換期間將忽略這些專案。
如果您只想為了它而使用遞回,那么這將是:
#ifdef MUST_USE_RECURSION_FOR_REASONS_UNKNOWN
void str_toupper (char* str)
{
static const char LUT[127] =
{
['a'] = 'A',
['b'] = 'B',
['c'] = 'C',
['d'] = 'D',
['e'] = 'E',
/* you get the idea */
};
if(*str == '\0')
return;
char converted = LUT[*str];
if(converted)
*str = converted;
str_toupper(str 1); // tail call
}
#endif
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/492597.html
