C语言 函数中使用指针反转字符串,main中输出乱码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4810393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 07:37:20  来源:igfitidea点击:

Reverse a string using pointers in a function, output in main is garbled

cpointers

提问by Gary

I'm trying to self-study C using C Primer Plusfrom Stephen Prata and one of the end-of-chapter exercises is to "Write a function that replaces the contents of a string with the string reversed.". This is a chapter on character strings with a good dose of pointers. I'm trying to use pointers as much as possible so I can better understand, but I'm stuck.

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

My problem is that when I print the value of the return pointer in main, it is garbled.

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

When I use gdb(just learning how to use that too), I can see that the memory address returned from my function is the same address that was used in the function and it's getting assigned to my pointer in main okay as far as I can tell.

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

I've tried so many things, what am I missing? FWIW I have not learned about malloc yet in the book, though I see it referenced on various www pages I've frequented trying to better understand C.

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


$ 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 <stdio.h>
#include <string.h>
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;
}

/*   A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
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
 = 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
 = 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)

回答by wich

You're returning a pointer to a local variable, (automatic variable to speak in ISO standard terms,) which is allocated on the stack, as soon as you return from your function that memory is released leaving you with a dangling pointer pointing to memory that may or may not still contain the string you put there, it depends entirely on circumstances. You should provide the output buffer as a function argument, or allocate it with malloc, or in C++ with new.

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

edit; added some example code

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

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

or

或者

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

回答by Dat Chu

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

The above code will make s2 points to a character string on the stack. This ar3 variable will be deleted once your function finishes.

上面的代码会让s2指向栈上的一个字符串。一旦您的函数完成,这个 ar3 变量将被删除。

You should output to some variable that you have pre-allocated. Modify it as follow

您应该输出到您预先分配的某个变量。修改如下

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)] = '
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);
}
'; }

Of course, once you get to the chapter regarding malloc, you can allocate the necessary memory for s3 depending on the length of s1. Until then, read on and have fun.

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

回答by Blastfurnace

The problem description sounds like you can just reverse the string in place. Keep it simple.

问题描述听起来像您可以将字符串原地反转。把事情简单化。

/*   A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
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] = '
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
'; if (string[1] != '
#include <stdio.h>
#include <string.h>

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);
}
') { //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; }

回答by aschepler

s2points to your local ar3array. Therefore when str_revreturns, it is no longer valid to look at the memory where ar3was via s2. Now s2is called a dangling pointer, and this is one of the huge pains in learning to use C pointers correctly.

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

For a simple solution that doesn't use mallocand meets the exercise requirement of "replaces the contents of a string", try copying the result into the function argument pointer (the original string; but be careful since your current code has since changed the pointer string). You know this pointer points at memory with enough characters and isn't local to your function.

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

回答by William

Part of the problem is that you can't actually "replace the contents of a string with the string reversed" when you are dealing with string literals, ie. strings delcared in the form char * s1 = "abcd";

部分问题在于,当您处理字符串文字时,您实际上无法“用反转的字符串替换字符串的内容”,即。以表格形式声明的字符串char * s1 = "abcd";

Without using literals, I made a relatively easy to understand recursive example:

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

##代码##

On my system the output is as follows:

在我的系统上,输出如下:

##代码##

回答by karthik gorijavolu

##代码##