在 C 中使用指针打印字符串
Using pointers in C to print string
我目前正在学习如何在 C 中使用指针和内存分配,并编写一个简单的代码片段来尝试使用指针打印字符串。我现在拥有的是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *aString(void)
{
char str[20];
strcpy(str, "Hello World!");
return str;
}
int main(int argc, char **argv)
{
char *ptr = malloc(20);
ptr = aString();
printf("%s\n", ptr);
free(ptr);
exit(0);
}
它只打印一个空行并告诉我对 free 的调用使用了一个无效指针。谁能花时间解释一下我在哪里思考问题的方式不对?
编辑:谢谢大家的回答,我正在通读。
在 String 上,str 在堆栈上分配,并在退出时由 stack unwinding 自动释放。
函数aString()
中声明的数组str[20]
为allocated in the program stack。当程序退出 aString()
时,这个数组被弹出内存,不再可访问,从而使 ptr
指向一个无效指针。
另一方面,malloc()
函数从堆中分配内存,可以在aString()
:
中使用
char *aString() {
char *str = malloc(20);
strcpy(str, "Hello World!");
return str;
}
然后在你的 main()
:
char *ptr = aString();
printf("%s\n", ptr);
free(ptr);
关于什么是栈和堆有很好的解释In this link。
您的代码正在 aString
的本地堆栈上创建数组 str[20]
。
当函数 aString
调用 return
时,它使用的堆栈被清除。
这包括您随后尝试在主函数中使用的数组 str[20]
。
如果您希望在函数返回后能够使用该数组,您需要将内存放在堆上。在函数 returns.
之后没有清理
或者传递一个存储数组的地方给函数。
我在下面包含了一个堆分配示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 20
char *aString(void)
{
/**
* create an array of 20 characters on the heap.
* This memory is not guaranteed to be all 0.
* You may want to memset the memory to 0, or use calloc.
*/
char* str = malloc( MAX_SIZE );
/* copy a max of 20 characters into the array you just created */
/* snprintf guarantees a null terminator, which is important. */
snprintf( str, MAX_SIZE, "Hello World!" );
return str;
}
int main(int argc, char **argv)
{
char *ptr;
ptr = aString();
printf("%s\n", ptr);
free(ptr); /* clear the heap memory, this is not needed for stack */
exit(0);
}
海峡[20];存在于堆栈中,并且在您从 aString return 之后引用它是无效的。
char *aString(void)
{
char *str;
str = malloc(20);
strcpy(str, "Hello World!");
return str;
}
int main(int argc, char **argv)
{
char *ptr = aString();
printf("%s\n", ptr);
free(ptr);
exit(0);
}
老实说,我不确定您的代码是如何在没有警告的情况下编译的,但是当我编写代码并尝试编译时,我收到了 return-local-address 警告。使用 -Wall
标志检查所有可能的警告。
基本上你所做的是创建一个字符数组,你的str[20]
,并试图return并在它声明的范围之外使用它。
相反,您可以让 aString()
将 char *string
和 strcpy
类型的参数直接带入 string
。
void aString(char *string) {
strcpy(string, "Hello World!");
}
你对两个概念的思考是错误的。
返回函数的局部对象不是一个好主意。
char *aString(void)
{
char str[20];
strcpy(str, "Hello World!");
return str;
}
因为 str
的内存在从 aString
执行 return 后被释放,函数 return 的指针可能不再指向有效内存。
从指针复制不会自动复制它持有的任何值。
char *ptr = malloc(20);
ptr = aString();
忽略 aString
return 指向不再存在的对象的指针的问题,您实际上是在这样做:
/*
* NOT valid C syntax
*/
ptr = AllocateMemory(ByteCount=20)
// ptr now points to address 0x10 where at least 20 bytes are available.
ptr = aString()
// ptr now points to address 0x1010. The 20 bytes allocated above can
// no longer be freed using ptr.
首先要做的是纠正复制情况:
// Copy a maximum of 20 bytes --
// the number of bytes allocated for the object that "ptr" points to.
strncpy(ptr, aString(), 20);
// If there were 20 bytes copied, and the last one was not the null character,
// "ptr" is not null-terminated. As a result, the string is forcibly truncated here.
// While ordinarily bad design, this is not meant to be robust.
ptr[19] = 0;
但是,您仍在 return 函数局部对象的地址,这意味着 strncpy
将尝试复制 return 由 [=19] 编辑的不存在的字符串=].这是解决问题的第二次尝试:
char *aString (char *s, size_t n) {
strncpy(s, "Hello World!", n);
s[n - 1] = 0;
return s;
}
...
char *ptr = malloc(20);
aString(ptr, 20);
printf("%s\n", ptr);
此外,您确实应该添加检查以确保 malloc
在尝试使用 ptr
之前根本没有 return 空指针。大多数示例代码为简洁起见省略了它。有些系统总是return一个非空指针,但无论如何还是安全点好。始终检查您的 return 值。 ;-)
[警告!太多的解释]这是你的代码逐行发生的事情:
char *ptr = malloc(20);分配了 20 字节大小的内存,ptr 指向它。
ptr = aString();你说 ptr 不再指向创建的 20 字节内存,而是指向这个叫做 'aString()' 的东西 [这使你的第一行无用]。所以现在让我们看看 aString() 必须带来什么,因为 ptr 即将指向它。
字符海峡[20];创建了一个大小为 20 的字符数组,str 是指向它的指针(最好记住数组的名称只是指向第一个元素的指针)。
strcpy(str, "Hello World!"); str指向大约12个字符的数组。
return海峡; str 是 returned,它是字符数组第一个元素的地址。这只是一个堆栈内存的地址,其中包含一个局部变量,该变量一旦退出函数就不再存在。所以现在回到主
ptr = aString();现在意味着 ptr 指向什么都没有的地址
*ptr = *aString(); // put the content pointed by aString() to ptr 20byte memory.
这会更有意义,因为它将把第一个字符 H 放在 ptr 中,因为那是 return str;带来。但是如果你在 aString 函数中分配内存,那么你就有了你想要的。
char *aString(void)
{
char *str = malloc(20);
strcpy(str, "Hello World!");
return str;
}
int main(int argc, char **argv)
{
char *ptr;
ptr = aString();
printf("%s\n", ptr);
free(ptr);
exit(0);
}
我目前正在学习如何在 C 中使用指针和内存分配,并编写一个简单的代码片段来尝试使用指针打印字符串。我现在拥有的是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *aString(void)
{
char str[20];
strcpy(str, "Hello World!");
return str;
}
int main(int argc, char **argv)
{
char *ptr = malloc(20);
ptr = aString();
printf("%s\n", ptr);
free(ptr);
exit(0);
}
它只打印一个空行并告诉我对 free 的调用使用了一个无效指针。谁能花时间解释一下我在哪里思考问题的方式不对?
编辑:谢谢大家的回答,我正在通读。
在 String 上,str 在堆栈上分配,并在退出时由 stack unwinding 自动释放。
函数aString()
中声明的数组str[20]
为allocated in the program stack。当程序退出 aString()
时,这个数组被弹出内存,不再可访问,从而使 ptr
指向一个无效指针。
另一方面,malloc()
函数从堆中分配内存,可以在aString()
:
char *aString() {
char *str = malloc(20);
strcpy(str, "Hello World!");
return str;
}
然后在你的 main()
:
char *ptr = aString();
printf("%s\n", ptr);
free(ptr);
关于什么是栈和堆有很好的解释In this link。
您的代码正在 aString
的本地堆栈上创建数组 str[20]
。
当函数 aString
调用 return
时,它使用的堆栈被清除。
这包括您随后尝试在主函数中使用的数组 str[20]
。
如果您希望在函数返回后能够使用该数组,您需要将内存放在堆上。在函数 returns.
之后没有清理或者传递一个存储数组的地方给函数。
我在下面包含了一个堆分配示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 20
char *aString(void)
{
/**
* create an array of 20 characters on the heap.
* This memory is not guaranteed to be all 0.
* You may want to memset the memory to 0, or use calloc.
*/
char* str = malloc( MAX_SIZE );
/* copy a max of 20 characters into the array you just created */
/* snprintf guarantees a null terminator, which is important. */
snprintf( str, MAX_SIZE, "Hello World!" );
return str;
}
int main(int argc, char **argv)
{
char *ptr;
ptr = aString();
printf("%s\n", ptr);
free(ptr); /* clear the heap memory, this is not needed for stack */
exit(0);
}
海峡[20];存在于堆栈中,并且在您从 aString return 之后引用它是无效的。
char *aString(void)
{
char *str;
str = malloc(20);
strcpy(str, "Hello World!");
return str;
}
int main(int argc, char **argv)
{
char *ptr = aString();
printf("%s\n", ptr);
free(ptr);
exit(0);
}
老实说,我不确定您的代码是如何在没有警告的情况下编译的,但是当我编写代码并尝试编译时,我收到了 return-local-address 警告。使用 -Wall
标志检查所有可能的警告。
基本上你所做的是创建一个字符数组,你的str[20]
,并试图return并在它声明的范围之外使用它。
相反,您可以让 aString()
将 char *string
和 strcpy
类型的参数直接带入 string
。
void aString(char *string) {
strcpy(string, "Hello World!");
}
你对两个概念的思考是错误的。
返回函数的局部对象不是一个好主意。
char *aString(void) { char str[20]; strcpy(str, "Hello World!"); return str; }
因为
str
的内存在从aString
执行 return 后被释放,函数 return 的指针可能不再指向有效内存。从指针复制不会自动复制它持有的任何值。
char *ptr = malloc(20); ptr = aString();
忽略
aString
return 指向不再存在的对象的指针的问题,您实际上是在这样做:/* * NOT valid C syntax */ ptr = AllocateMemory(ByteCount=20) // ptr now points to address 0x10 where at least 20 bytes are available. ptr = aString() // ptr now points to address 0x1010. The 20 bytes allocated above can // no longer be freed using ptr.
首先要做的是纠正复制情况:
// Copy a maximum of 20 bytes --
// the number of bytes allocated for the object that "ptr" points to.
strncpy(ptr, aString(), 20);
// If there were 20 bytes copied, and the last one was not the null character,
// "ptr" is not null-terminated. As a result, the string is forcibly truncated here.
// While ordinarily bad design, this is not meant to be robust.
ptr[19] = 0;
但是,您仍在 return 函数局部对象的地址,这意味着 strncpy
将尝试复制 return 由 [=19] 编辑的不存在的字符串=].这是解决问题的第二次尝试:
char *aString (char *s, size_t n) {
strncpy(s, "Hello World!", n);
s[n - 1] = 0;
return s;
}
...
char *ptr = malloc(20);
aString(ptr, 20);
printf("%s\n", ptr);
此外,您确实应该添加检查以确保 malloc
在尝试使用 ptr
之前根本没有 return 空指针。大多数示例代码为简洁起见省略了它。有些系统总是return一个非空指针,但无论如何还是安全点好。始终检查您的 return 值。 ;-)
[警告!太多的解释]这是你的代码逐行发生的事情:
char *ptr = malloc(20);分配了 20 字节大小的内存,ptr 指向它。
ptr = aString();你说 ptr 不再指向创建的 20 字节内存,而是指向这个叫做 'aString()' 的东西 [这使你的第一行无用]。所以现在让我们看看 aString() 必须带来什么,因为 ptr 即将指向它。
字符海峡[20];创建了一个大小为 20 的字符数组,str 是指向它的指针(最好记住数组的名称只是指向第一个元素的指针)。
strcpy(str, "Hello World!"); str指向大约12个字符的数组。
return海峡; str 是 returned,它是字符数组第一个元素的地址。这只是一个堆栈内存的地址,其中包含一个局部变量,该变量一旦退出函数就不再存在。所以现在回到主
ptr = aString();现在意味着 ptr 指向什么都没有的地址
*ptr = *aString(); // put the content pointed by aString() to ptr 20byte memory.
这会更有意义,因为它将把第一个字符 H 放在 ptr 中,因为那是 return str;带来。但是如果你在 aString 函数中分配内存,那么你就有了你想要的。
char *aString(void)
{
char *str = malloc(20);
strcpy(str, "Hello World!");
return str;
}
int main(int argc, char **argv)
{
char *ptr;
ptr = aString();
printf("%s\n", ptr);
free(ptr);
exit(0);
}