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

时间:2011-01-26 21:45:45

标签: c pointers

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

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

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

我尝试了很多东西,我错过了什么? 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 <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;
}

6 个答案:

答案 0 :(得分:3)

你正在返回一个指向局部变量的指针(用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;
}

答案 1 :(得分:2)

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

上面的代码会使s2指向堆栈上的字符串。一旦你的功能完成,这个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分配必要的内存。在此之前,请继续阅读并享受乐趣。

答案 2 :(得分:2)

问题描述听起来像你可以将字符串反转到位。保持简单。

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

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

形式的字符串

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

/*   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] = '\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

答案 5 :(得分:0)

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