使用指针在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
手动释放之前仍然有效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
手动释放之前仍然有效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);
}
...