在 C 中,指针的值改变后内存值会发生什么变化?
In C, what happens to memory values after a pointer's value is changed?
在下面的代码中,我将一个指针按值传递给一个函数,我希望将 N 个字符串连接到原始字符串上。
按照我编写的方式,我通过计算出要添加到原始字符串长度上的字节数来分配新内存。
然后填充这个新字符串,并return编辑指向该字符串的指针。
所以,假设原始指针 msg
是 0x000001
,它指向字符串 "Hello[=13=]"
.
的起始字符
然后在函数中,一个新的指针strNew
最终指向"Hello world, poop[=15=]"
,并且值为0x0000f5
,新字符串的内存所在。
然后,作为函数的 return,msg
指针的值现在是 0x0000f5
。
我的问题是,位于 0x000001
的内存发生了什么?它包含 "Hello[=13=]"
的字节,但不再有指向它的指针。它会收集垃圾吗?这是个问题吗?我应该用 ' ' 字符以某种方式覆盖内容吗?
如果没有,我如何从 strcatcat() 函数中释放它?
我们的想法是不必担心字符数组足够大以作为字符串的开头。这不合理吗?
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
char * strcatcat(char * orig, const char* strArgs, ...){
va_list valist;
unsigned long initStrLength = strlen(orig);
// work out how much me to realloc
unsigned long moreBytes = 0;
va_start(valist, strArgs);
const char* str = strArgs;
while (str != NULL ) {
moreBytes += strlen(str);
str = va_arg(valist, const char *);
}
// define a new char pointer to populate, of defined size
char * strNew = NULL;
strNew = (char *) malloc((moreBytes + initStrLength+1));
// copy the original string into the start
strcpy(strNew, orig);
//reset, then go through and concat into new string
va_start(valist, strArgs);
str = strArgs;
while (str != NULL ) {
strcat(strNew, str);
str = va_arg(valist, const char *);
}
// close list
va_end(valist);
// return this pointer
return strNew;
}
int main()
{
char * msg = "Hello";
msg = strcatcat(msg, " World, ", "poop", NULL);
printf("%s\n", msg);
return 0;
}
编辑:谢谢大家,问题已经解决了。我习惯了更高级别的语言,如 PHP、C# 等,并且在阅读有关指针算法的文章时突然出现了这个问题,我找不到不关注指针而不是指针值的答案。
未来人们的 TLDR - 如果没有调用者管理它,我给出的示例将导致内存泄漏。 main 中的指针需要复制才能释放。
My question is, what happens to the memory located at 0x000001?? It
contains bytes for "Hello[=17=]", but there is no longer a pointer to it.
Does it get garbage collected? Is it a problem? Should I overwrite the
contents somehow with ' ' chars?
对于初学者来说,C 语言没有垃圾收集器。其次,您不能更改字符串文字。任何更改字符串文字的尝试都会导致未定义的行为。
在此声明中
char * msg = "Hello";
声明了一个指向字符串文字第一个字符的指针 "Hello"
。字符串文字本身具有静态存储持续时间,并且在程序完成执行之前一直有效,而与指针 msg
的值是否更改无关。
你可以这样想象
char unnamed_string_literal[] = { 'H', 'e', 'l', 'l', 'o', '[=11=]' };
int main( void )
{
char *msg = unnamed_string_literal;
//...
}
你不应该为字符串文字操心。
例如考虑以下有效程序。
#include <stdio.h>
int main(void)
{
char *msg = "Hello";
printf( "%s ", msg );
msg = "World!";
puts( msg );
return 0;
}
程序输出为
Hello World!
本质上这个程序与下面的程序相似(除了问题上下文中的一些不重要的细节)
#include <stdio.h>
char word1[] = { 'H', 'e', 'l', 'l', 'o', '[=14=]' };
char word2[] = { 'W', 'o', 'r', 'l', 'd', '!', '[=14=]' };
int main(void)
{
char *msg = word1;
printf( "%s ", msg );
msg = word2;
puts( msg );
return 0;
}
首先,如果您为“Hello[=30=]”动态分配内存并且不释放它,则会造成内存泄漏。这是一个如何制作的学校示例。
这导致下一个认识:C 中没有垃圾收集器,除非您创建一个。你对一切负责。这就是 C 语言的美妙之处,因为你也可以控制一切。您有权决定针对您的特定问题的最佳方法。
下一个问题是,在函数内部,您永远不知道内存是如何分配的。我可以在调用者级别创建 char example[100] = "My value";
并将其分配在堆栈上。如果您尝试从函数内部释放它,程序将失败。
解决这个问题的基本方法很少:
- 调用方提供缓冲区,如果缓冲区不够大则函数失败
- 该函数分配内存并且不接触输入,调用者对其接收的所有内容负责。
- 更高级别的字符串抽象(我会说 C++ 中的 class,但让我们说一些具有一些相关操作的类型)一个例子可能是 Glib String https://developer.gnome.org/glib/stable/glib-Strings.html
, 但还有许多其他实现。
它们各有优缺点(防止泄漏、内存碎片等)。这是由 C 程序员来决定哪种方法最适合您的情况。
My question is, what happens to the memory located at 0x000001?? It contains bytes for "Hello[=16=]", but there is no longer a pointer to it.
什么都没发生...指针只不过是一些内存的地址,所以改变指针的值只会改变它指向的字节,它不会影响存储在指向的字节中的值到.
Does it get garbage collected?
C 没有内置的垃圾收集器;你负责管理内存。
Is it a problem?
也许……要看情况。对于 strcatcat()
函数,正如您观察到的那样,指针 orig
是按值传递的。这意味着该函数获得了它自己的指针副本,并且如果该函数更改了 orig
的值,则调用者的指针副本根本不会改变。由于 strcatcat()
没有分配 orig
指向的内存,它不负责释放它......调用者(或分配或负责该块的人)应该这样做。
如果您的程序分配内存块并且从不释放它们,那肯定是个问题,因此总的来说您应该有一个清晰的内存管理策略。但是除非您非常清楚调用 strcatcat()
会释放传入的块,否则该函数不应触及原始块。
Should I overwrite the contents somehow with ' ' chars?
你为什么要这么做?即使在调用您的函数之后,调用者是否可能还想将原始块用于其他用途?
当您解除分配时,字节不会停止存在;他们总是在那里。分配只是为特定目的保留给定字节范围的过程,这样其他一些代码就不会尝试同时使用相同的字节。当您释放内存时,字节仍保留在那里,但您释放的块可用于其他用途。如果数据在某种程度上是敏感的,例如,在释放块之前覆盖数据是有意义的。密码或某种个人信息。但是只要不需要保护块中的数据,就没有必要在释放内存之前清除内存。
在下面的代码中,我将一个指针按值传递给一个函数,我希望将 N 个字符串连接到原始字符串上。
按照我编写的方式,我通过计算出要添加到原始字符串长度上的字节数来分配新内存。
然后填充这个新字符串,并return编辑指向该字符串的指针。
所以,假设原始指针 msg
是 0x000001
,它指向字符串 "Hello[=13=]"
.
然后在函数中,一个新的指针strNew
最终指向"Hello world, poop[=15=]"
,并且值为0x0000f5
,新字符串的内存所在。
然后,作为函数的 return,msg
指针的值现在是 0x0000f5
。
我的问题是,位于 0x000001
的内存发生了什么?它包含 "Hello[=13=]"
的字节,但不再有指向它的指针。它会收集垃圾吗?这是个问题吗?我应该用 ' ' 字符以某种方式覆盖内容吗?
如果没有,我如何从 strcatcat() 函数中释放它?
我们的想法是不必担心字符数组足够大以作为字符串的开头。这不合理吗?
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
char * strcatcat(char * orig, const char* strArgs, ...){
va_list valist;
unsigned long initStrLength = strlen(orig);
// work out how much me to realloc
unsigned long moreBytes = 0;
va_start(valist, strArgs);
const char* str = strArgs;
while (str != NULL ) {
moreBytes += strlen(str);
str = va_arg(valist, const char *);
}
// define a new char pointer to populate, of defined size
char * strNew = NULL;
strNew = (char *) malloc((moreBytes + initStrLength+1));
// copy the original string into the start
strcpy(strNew, orig);
//reset, then go through and concat into new string
va_start(valist, strArgs);
str = strArgs;
while (str != NULL ) {
strcat(strNew, str);
str = va_arg(valist, const char *);
}
// close list
va_end(valist);
// return this pointer
return strNew;
}
int main()
{
char * msg = "Hello";
msg = strcatcat(msg, " World, ", "poop", NULL);
printf("%s\n", msg);
return 0;
}
编辑:谢谢大家,问题已经解决了。我习惯了更高级别的语言,如 PHP、C# 等,并且在阅读有关指针算法的文章时突然出现了这个问题,我找不到不关注指针而不是指针值的答案。
未来人们的 TLDR - 如果没有调用者管理它,我给出的示例将导致内存泄漏。 main 中的指针需要复制才能释放。
My question is, what happens to the memory located at 0x000001?? It contains bytes for "Hello[=17=]", but there is no longer a pointer to it. Does it get garbage collected? Is it a problem? Should I overwrite the contents somehow with ' ' chars?
对于初学者来说,C 语言没有垃圾收集器。其次,您不能更改字符串文字。任何更改字符串文字的尝试都会导致未定义的行为。
在此声明中
char * msg = "Hello";
声明了一个指向字符串文字第一个字符的指针 "Hello"
。字符串文字本身具有静态存储持续时间,并且在程序完成执行之前一直有效,而与指针 msg
的值是否更改无关。
你可以这样想象
char unnamed_string_literal[] = { 'H', 'e', 'l', 'l', 'o', '[=11=]' };
int main( void )
{
char *msg = unnamed_string_literal;
//...
}
你不应该为字符串文字操心。
例如考虑以下有效程序。
#include <stdio.h>
int main(void)
{
char *msg = "Hello";
printf( "%s ", msg );
msg = "World!";
puts( msg );
return 0;
}
程序输出为
Hello World!
本质上这个程序与下面的程序相似(除了问题上下文中的一些不重要的细节)
#include <stdio.h>
char word1[] = { 'H', 'e', 'l', 'l', 'o', '[=14=]' };
char word2[] = { 'W', 'o', 'r', 'l', 'd', '!', '[=14=]' };
int main(void)
{
char *msg = word1;
printf( "%s ", msg );
msg = word2;
puts( msg );
return 0;
}
首先,如果您为“Hello[=30=]”动态分配内存并且不释放它,则会造成内存泄漏。这是一个如何制作的学校示例。
这导致下一个认识:C 中没有垃圾收集器,除非您创建一个。你对一切负责。这就是 C 语言的美妙之处,因为你也可以控制一切。您有权决定针对您的特定问题的最佳方法。
下一个问题是,在函数内部,您永远不知道内存是如何分配的。我可以在调用者级别创建 char example[100] = "My value";
并将其分配在堆栈上。如果您尝试从函数内部释放它,程序将失败。
解决这个问题的基本方法很少:
- 调用方提供缓冲区,如果缓冲区不够大则函数失败
- 该函数分配内存并且不接触输入,调用者对其接收的所有内容负责。
- 更高级别的字符串抽象(我会说 C++ 中的 class,但让我们说一些具有一些相关操作的类型)一个例子可能是 Glib String https://developer.gnome.org/glib/stable/glib-Strings.html , 但还有许多其他实现。
它们各有优缺点(防止泄漏、内存碎片等)。这是由 C 程序员来决定哪种方法最适合您的情况。
My question is, what happens to the memory located at 0x000001?? It contains bytes for "Hello[=16=]", but there is no longer a pointer to it.
什么都没发生...指针只不过是一些内存的地址,所以改变指针的值只会改变它指向的字节,它不会影响存储在指向的字节中的值到.
Does it get garbage collected?
C 没有内置的垃圾收集器;你负责管理内存。
Is it a problem?
也许……要看情况。对于 strcatcat()
函数,正如您观察到的那样,指针 orig
是按值传递的。这意味着该函数获得了它自己的指针副本,并且如果该函数更改了 orig
的值,则调用者的指针副本根本不会改变。由于 strcatcat()
没有分配 orig
指向的内存,它不负责释放它......调用者(或分配或负责该块的人)应该这样做。
如果您的程序分配内存块并且从不释放它们,那肯定是个问题,因此总的来说您应该有一个清晰的内存管理策略。但是除非您非常清楚调用 strcatcat()
会释放传入的块,否则该函数不应触及原始块。
Should I overwrite the contents somehow with ' ' chars?
你为什么要这么做?即使在调用您的函数之后,调用者是否可能还想将原始块用于其他用途?
当您解除分配时,字节不会停止存在;他们总是在那里。分配只是为特定目的保留给定字节范围的过程,这样其他一些代码就不会尝试同时使用相同的字节。当您释放内存时,字节仍保留在那里,但您释放的块可用于其他用途。如果数据在某种程度上是敏感的,例如,在释放块之前覆盖数据是有意义的。密码或某种个人信息。但是只要不需要保护块中的数据,就没有必要在释放内存之前清除内存。