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

使用指针在c中打印字符串,c,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;

我有以下代码:

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

出于某种原因,如果我在函数中打印字符串,我会得到正常的输入。但是如果我把它打印在主屏幕上,我得到的输出会非常wierd。有什么问题

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

char *string = malloc(100);  


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

char *string = malloc(100);  


当返回
GetString
中指向局部变量
string
的指针
string
时,返回的是对即将回收的内存的引用。这是因为
string
存在于
GetString
中,当函数返回时,堆栈帧不再存在。您有三种选择:

  • string
    移动到
    main
    ,并将指向它的指针传递到
    GetString
  • GetString
    内部使用
    malloc
    动态分配
    string
    。使用
    malloc
    分配的内存在使用
    free
    手动释放之前仍然有效
  • 或者,正如MichaelPetch在下面指出的,将
    string
    声明为
    static
    ,这意味着内存将在程序运行时被留出。但是,这意味着对
    GetString
    的后续调用将删除其内容,因此,如果您想将上一次调用的结果保存到
    GetString
    您必须使用
    strdup
    或类似工具手动复制它
  • GetString
    返回之前,堆栈如下所示:

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

    访问不属于堆栈的内容(即,在本例中位于堆栈指针下方)会导致未定义的行为。(好吧,不完全是这样-见下面巴拉克·马诺斯的评论)在你的例子中,你得到的是垃圾。

    当你返回
    string
    ,它是一个指向
    GetString
    中的局部变量
    string
    的指针时,你返回的是一个对即将回收的内存的引用。这是因为
    string
    存在于
    GetString
    中,当函数返回时,堆栈帧不再存在。您有三种选择:

  • string
    移动到
    main
    ,并将指向它的指针传递到
    GetString
  • GetString
    内部使用
    malloc
    动态分配
    string
    。使用
    malloc
    分配的内存在使用
    free
    手动释放之前仍然有效
  • 或者,正如MichaelPetch在下面指出的,将
    string
    声明为
    static
    ,这意味着内存将在程序运行时被留出。但是,这意味着对
    GetString
    的后续调用将删除其内容,因此,如果您想将上一次调用的结果保存到
    GetString
    您必须使用
    strdup
    或类似工具手动复制它
  • GetString
    返回之前,堆栈如下所示:

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

    访问不属于堆栈的内容(即,在本例中位于堆栈指针下方)会导致未定义的行为。(好吧,不完全是这样-见下面巴拉克·马诺斯的评论)在你的情况下,你会得到垃圾。

    你可以将数组传递给
    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';
    }
    

    您可以将数组传递给
    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';
    }
    

    [评论太长]

    如需跟进,请参阅以下内容:

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

    问题是
    string
    是一个局部变量,您可以返回指向它的指针。虽然不是对你的问题的回答(其他人的回答还行),但有一个观察结果是,如果读取的字符数超过99,则可能存在缓冲区溢出和安全威胁。可能应该检查
    计数器
    ,使其不超过数组的大小。此外,您不需要
    string
    。当数组出现在C语言的表达式中时,它(粗略地说)被转换成指向其第一个元素的指针,因此您可以简单地
    返回字符串
    。另一个问题是
    main
    中的代码不知道
    GetString
    函数是什么。如果您使用的是64位系统,那么您的编译器很可能会出错。您应该在编译代码时启用所有警告。问题是
    string
    是一个局部变量,您可以返回指向它的指针。虽然不是对你的问题的回答(其他人的回答还行),但有一个观察结果是,如果读取的字符数超过99,则可能存在缓冲区溢出和安全威胁。可能应该检查
    计数器
    ,使其不超过数组的大小。此外,您不需要
    string
    。当数组出现在C语言的表达式中时,它(粗略地说)被转换成指向其第一个元素的指针,因此您可以简单地
    返回字符串
    。另一个问题是
    main
    中的代码不知道
    GetString
    函数是什么。如果您使用的是64位系统,那么您的编译器很可能会出错。您应该在编译代码时启用所有警告。另一个选项(尽管有副作用)是将
    string
    定义为静态。值得注意的是,堆栈实现(特别是低/高地址问题)依赖于编译器,不受C语言标准的约束,这只说明返回本地数组会产生未定义的行为。感谢您指出这一点,@barakmanos。我已经相应地编辑了我的文章。另一个选项(尽管有副作用,但很难看)是将
    字符串定义为静态。值得注意的是,堆栈实现(特别是低/高地址问题)依赖于编译器,不受C语言标准的约束,C语言标准只规定返回
    
    int main()
    {
      char string[100];
    
      int result = GetString(string, sizeof(string));
      if (-1 == result)
      {
        perror("GetString()" failed");
        exit(1);
      }
    
      ...