使用指针在c中打印字符串

时间:2014-12-20 16:13:52

标签: c

我有以下代码:

#include <stdio.h>

int main()
{
    char * string = GetString();

    printf("%c", *(1+string));


    int j;

    for (j = 0; string[j] != '\0'; j++)
    printf("%c", *(j+string));

    int i;

    scanf("%d", &i);

    return 0;
}

和函数GetString

char *  GetString()
{
    char string[100];

    char x; // to get the chars 1 by 1
    int counter = 0;
    scanf("%c", &x); // i dont like do while loops

    while (x != '\n')
    {
        string[counter] = x;
        scanf("%c", &x);
        counter++;
    }
    string[counter] = '\0';

    char * stringg = string;

    return stringg;
}

由于某种原因,如果我在函数内打印字符串,我得到正常输入。但如果我在主打印它我真的很奇怪的输出。问题是什么 ?

4 个答案:

答案 0 :(得分:4)

当您返回stringgstring中指向本地变量GetString的指针时,您将返回对即将回收的内存的引用。这是因为string“生活”在GetString的{​​{3}}中,并且当函数返回时堆栈框架不再存在。您有三种选择:

  1. string移至main,并将指针传递给GetString
  2. 使用string内的malloc动态分配GetString。使用malloc分配的内存将一直存在,直到使用free手动释放。
  3. 或者,正如Michael Petch在下面指出的那样,将string声明为static,这意味着将在程序的stack frame中留出记忆。但是,这意味着后续调用GetString会破坏其内容,因此如果您想将之前调用的结果保存到 GetString您必须使用strdup或类似内容手动复制它。
  4. GetString返回之前,堆栈看起来像这样:

                           (high address)
    +---------------------+
    |   (main's frame)    |
    |        ...          |
    +---------------------+
    | (GetString's frame) |
    |  char string[100]   |
    +---------------------+ <- stack pointer
                           (low address)
    

    正如您所看到的,global data segment指向GetString框架的末尾,标志着堆栈的顶部(请注意,在大多数现代平台上,堆栈实际上向下增长)。但是当GetString返回时,堆栈指针向上移动到main的帧的末尾:

                           (high address)
    +---------------------+
    |   (main's frame)    |
    |        ...          |
    +---------------------+ <- stack pointer
    | Formerly the frame  |
    | of GetString, now   |
    | (probably) garbage. |
    +---------------------+
                           (low address)
    

    访问不属于堆栈的东西(即,在这种情况下,在堆栈指针下方)会导致未定义的行为。(好吧,不完全 - 请参阅下面的Barak Manos的评论)你的情况,你得到垃圾。

答案 1 :(得分:2)

返回指向自动局部变量的指针会调用未定义的行为。您需要使用动态分配或使用static说明符。

char *string = malloc(100);  

static char string[100];

答案 2 :(得分:0)

您可以将数组传递给GetString函数

void  GetString(char string[], size_t length /* prevent overflow */)
{
    char x; // to get the chars 1 by 1
    int counter = 0;

    if (length == 0)
    {
        string[0] = '\0';
        return;
    }
    scanf("%c", &x); // i dont like do while loops

    while ((x != '\n') && (counter < length - 1))
    {
        string[counter] = x;
        scanf("%c", &x);
        counter++;
    }
    string[counter] = '\0';
}

并在main

int main()
{
    char string[100];

    GetString(string, sizeof(string));
    if (*string != '0')
        printf("%c", *(1+string));

    int j;
    for (j = 0; string[j] != '\0'; j++)
        printf("%c", *(j+string));
    int i;
    scanf("%d", &i);

    return 0;
}

答案 3 :(得分:0)

[评论太久了]

要跟进iharob proposal to pass in the buffer,请参阅:

int GetString(char * str, size_t len)
{
  int result = 0;

  if ((NULL == str) || (0 == len))
  {
    result = -1;
    errno = EINVAL;
  }
  else 
  {
    while (1 < len)
    {
      result = scanf("%c", str);
      if (EOF == result)
      {
        int errno_save = errno:

        if (ferror(stdin))
        {
          result = -1;
          errno = errno_save;
        }
        else
        {
          result = 0;
        }
      }

      if ((0 != result) || ('\n' == *str))
      {
        break;
      }

      ++str;
      --len;
    }

    *str = '\0';
  }

  return result;
}

这样称呼:

int main()
{
  char string[100];

  int result = GetString(string, sizeof(string));
  if (-1 == result)
  {
    perror("GetString()" failed");
    exit(1);
  }

  ...