使用函数中的指针反转字符串,main中的输出是乱码

我正在尝试使用Stephen Prata的C Primer Plus自学C,其中一个章末练习是“编写一个用字符串反转替换字符串内容的函数”。 这是一个关于具有良好指针的字符串的章节。 我试图尽可能多地使用指针,所以我可以更好地理解,但我被卡住了。

我的问题是,当我在main中打印返回指针的值时,它是乱码。

当我使用gdb(只是学习如何使用它)时,我可以看到从我的函数返回的内存地址与函数中使用的内存地址相同,并且它已被主动分配给我的指针,尽管我可以告诉。

我尝试了很多东西,我错过了什么? FWIW我还没有在书中了解过malloc,虽然我看到它在我经常尝试更好地理解C的各种www页面上引用。

$ cc -o exercise8 exercise8.c && ./exercise8 This is s1 before: abcd This is s2 in function: dcba This is s3 after: d`! /* A function that replaces the contents of a string with the string reversed. */ #include  #include  char *str_rev(char * string); int main(void) { char * s1 = "abcd"; char * s3; printf("This is s1 before: %s\n", s1); s3 = str_rev(s1); printf("This is s3 after: %s\n", s3); } char *str_rev(char * string) { char ar3[5]; char * s2; int len = 0; s2 = ar3; len = (strlen(string) - 1); string = string + len; while ( len >= 0 ) { *s2 = *string; len--; string--; s2++; } s2++; *s2 = 0; s2 = s2 - 5; printf("This is s2 in function: %s\n", s2); return s2; } $ gdb exercise8 GNU gdb (GDB) 7.1-ubuntu Reading symbols from exercise8...done. (gdb) break 12 Breakpoint 1 at 0x804844a: file exercise8.c, line 12. (gdb) break 40 Breakpoint 2 at 0x80484d9: file exercise8.c, line 40. (gdb) run Starting program: exercise8 This is s1 before: abcd // My original string. This is s2 in function: dcba // Good, my reversed string while in the function. Breakpoint 2, str_rev (string=0xbffff043 "dcba") at exercise8.c:40 40 return s2; (gdb) print s2 $1 = 0xbffff043 "dcba" // Location of pointer s2. (gdb) continue Continuing. Breakpoint 1, main () at exercise8.c:12 12 printf("This is s3 after: %s\n", s3); (gdb) print s3 $2 = 0xbffff043 "dcba" // Back in main same pointer as s2 from function. (gdb) step This is s3 after: d`Q // Line 12 executed. Output garbled. 14 } (gdb) 
 $ cc -o exercise8 exercise8.c && ./exercise8 This is s1 before: abcd This is s2 in function: dcba This is s3 after: d`! /* A function that replaces the contents of a string with the string reversed. */ #include  #include  char *str_rev(char * string); int main(void) { char * s1 = "abcd"; char * s3; printf("This is s1 before: %s\n", s1); s3 = str_rev(s1); printf("This is s3 after: %s\n", s3); } char *str_rev(char * string) { char ar3[5]; char * s2; int len = 0; s2 = ar3; len = (strlen(string) - 1); string = string + len; while ( len >= 0 ) { *s2 = *string; len--; string--; s2++; } s2++; *s2 = 0; s2 = s2 - 5; printf("This is s2 in function: %s\n", s2); return s2; } $ gdb exercise8 GNU gdb (GDB) 7.1-ubuntu Reading symbols from exercise8...done. (gdb) break 12 Breakpoint 1 at 0x804844a: file exercise8.c, line 12. (gdb) break 40 Breakpoint 2 at 0x80484d9: file exercise8.c, line 40. (gdb) run Starting program: exercise8 This is s1 before: abcd // My original string. This is s2 in function: dcba // Good, my reversed string while in the function. Breakpoint 2, str_rev (string=0xbffff043 "dcba") at exercise8.c:40 40 return s2; (gdb) print s2 $1 = 0xbffff043 "dcba" // Location of pointer s2. (gdb) continue Continuing. Breakpoint 1, main () at exercise8.c:12 12 printf("This is s3 after: %s\n", s3); (gdb) print s3 $2 = 0xbffff043 "dcba" // Back in main same pointer as s2 from function. (gdb) step This is s3 after: d`Q // Line 12 executed. Output garbled. 14 } (gdb) 
 $ cc -o exercise8 exercise8.c && ./exercise8 This is s1 before: abcd This is s2 in function: dcba This is s3 after: d`! /* A function that replaces the contents of a string with the string reversed. */ #include  #include  char *str_rev(char * string); int main(void) { char * s1 = "abcd"; char * s3; printf("This is s1 before: %s\n", s1); s3 = str_rev(s1); printf("This is s3 after: %s\n", s3); } char *str_rev(char * string) { char ar3[5]; char * s2; int len = 0; s2 = ar3; len = (strlen(string) - 1); string = string + len; while ( len >= 0 ) { *s2 = *string; len--; string--; s2++; } s2++; *s2 = 0; s2 = s2 - 5; printf("This is s2 in function: %s\n", s2); return s2; } $ gdb exercise8 GNU gdb (GDB) 7.1-ubuntu Reading symbols from exercise8...done. (gdb) break 12 Breakpoint 1 at 0x804844a: file exercise8.c, line 12. (gdb) break 40 Breakpoint 2 at 0x80484d9: file exercise8.c, line 40. (gdb) run Starting program: exercise8 This is s1 before: abcd // My original string. This is s2 in function: dcba // Good, my reversed string while in the function. Breakpoint 2, str_rev (string=0xbffff043 "dcba") at exercise8.c:40 40 return s2; (gdb) print s2 $1 = 0xbffff043 "dcba" // Location of pointer s2. (gdb) continue Continuing. Breakpoint 1, main () at exercise8.c:12 12 printf("This is s3 after: %s\n", s3); (gdb) print s3 $2 = 0xbffff043 "dcba" // Back in main same pointer as s2 from function. (gdb) step This is s3 after: d`Q // Line 12 executed. Output garbled. 14 } (gdb) 

 char ar3[5]; char * s2 = ar3; 

上面的代码将使s2指向堆栈上的字符串。 一旦你的function完成,这个ar3变量将被删除。

您应该输出一些您已预先分配的变量。 修改如下

 int main(void) { char * s1 = "abcd"; char s3[5]; printf("This is s1 before: %s\n", s1); str_rev(s1, s3); printf("This is s3 after: %s\n", s3); } void str_rev(char * string, char * s2) { ........ // don't return // Also assign the last character with the NULL terminator ar2[strlen(string)] = '\0'; } 

当然,一旦你进入关于malloc的章节,你可以根据s1的长度为s3分配必要的内存。 在此之前,请继续阅读并享受乐趣。

你正在返回一个指向局部变量的指针(自动变量用ISO标准来说),它是在堆栈上分配的,只要你从你的函数返回释放内存,你就会有一个指向内存的悬空指针可能会或可能不会包含您放在那里的字符串,这完全取决于具体情况。 您应该将输出缓冲区作为函数参数提供,或者使用malloc分配它,或者在C ++中使用new分配它。

编辑; 添加了一些示例代码

 void reverse(const char* s1, char* s2) { const int l = strlen(s1); const char* p = s1 + l - 1; do { *s2++ = *p; } while (p-- != s1); *s2 = 0; } int main() { // some code here char s1[5] = "abcd"; char s2[5] = ""; reverse(s1, s2); // some more code here return 0; } 

要么

 char* reverse(const char* s) { const int l = strlen(s); char* rs = malloc(l+1); const char* p = s + l - 1; do { *rs++ = *p; } while (p-- != s); *rs = 0; return rs - l; } int main() { // some code here char s1[5] = "abcd"; char* s2 = reverse(s1); // some more code here free(s2); return 0; } 

问题描述听起来像你可以反转字符串到位。 把事情简单化。

 void reverse_range(char *first, char *last) // [first, last) { for (; first != last && first != --last; ++first) { char temp = *first; *first = *last; *last = temp; } } void reverse(char *str) { reverse_range(str, str + strlen(str)); } int main() { char text[] = "0123456789"; printf("before: %s\n", text); reverse(text); printf("after : %s\n", text); } 

s2指向您当地的ar3arrays。 因此,当str_rev返回时,查看ar3通过s2的内存不再有效。 现在s2被称为悬空指针,这是学习正确使用C指针的巨大痛苦之一。

对于不使用malloc并满足“替换字符串内容”的练习要求的简单解决方案,请尝试将结果复制到函数参数指针(原始string ;但要小心,因为您当前的代码已经更改了指针string )。 你知道这个指针指向内存中有足够的字符,并且不是你的函数本地的。

部分问题是当你处理字符串文字时,你实际上不能“用字符串反转替换字符串的内容”,即。 char * s1 = "abcd";forms的字符串char * s1 = "abcd";

不使用文字,我做了一个相对容易理解的递归示例:

 /* A function that replaces the contents of a string with the string reversed. */ #include  #include  void str_rev(char * string); int main(void) { char s1[] = "abc"; char s2[] = "even"; char s3[] = "quodd"; printf("This is s1 before: %s\n", s1); str_rev(s1); printf("This is s1 after: %s\n", s1); printf("This is s2 before: %s\n", s2); str_rev(s2); printf("This is s2 after: %s\n", s2); printf("This is s3 before: %s\n", s3); str_rev(s3); printf("This is s3 after: %s\n", s3); return 0; } void str_rev(char * string) { //Store the first char of the string locally char firstChar = string[0]; //Store the last char of the string locally int lastCharPos = strlen(string)-1; char lastChar = string[lastCharPos]; //Shorten the string (temporarily) string[lastCharPos] = '\0'; if (string[1] != '\0') { //Call on the now shortened string, eg. //"abc" becomes "b" //"even" becomes "ve" //"quodd" becomes "uod" str_rev(string+1); } //Swap the first and last characters string[0] = lastChar; string[lastCharPos] = firstChar; } 

在我的系统上输出如下:

 This is s1 before: abc This is s1 after: cba This is s2 before: even This is s2 after: neve This is s3 before: quodd This is s3 after: ddouq 
 #include  #include  void my_strrev(char* begin){ char temp; char* end; end = begin + strlen(begin)-1; while(end>begin){ temp = *end; *end = *begin; *begin = temp; end--; begin++; } } main(){ char string[]= "foobar"; my_strrev(string); printf("%s", string); }