使用 malloc() 函数和指针理解代码
Understanding code with use of the malloc() function and pointers
我正在尝试记录一些代码以提高我对指针的了解和一般的 ANSI C 能力。
...
int static_store = 30;
const char * pcg = "String Literal";
int main()
{
int auto_store = 40;
char auto_string[] = "Auto char Array";
int * pi;
char * pcl;
pi = (int *) malloc(sizeof(int));
*pi = 35;
pcl = (char *) malloc(strlen("Dynamic String") + 1);
strcpy(pcl, "Dynamic String");
...
乍一看,初始化了两个指针,pi和pcl,分别是int和char类型。
但是后面的几行让我很困惑,我不明白发生了什么。我可以看到正在调用 malloc 来分配 int (40) 大小的内存。是给变量pi和pcl分配内存吗?
2 个指针被 delcared(pi
和 pcl
)。在声明时,它们 未 初始化。
pi
然后指向一个堆分配的内存块,该内存块可以容纳 1 个 int(其大小取决于平台,但通常为 4 个字节)分配有函数 maloc
。在某处必须使用函数 free
显式释放此内存 - 不这样做将导致内存泄漏。
然后将 int 值 35 存储在该内存位置。 *pi
可以读作 "what the pointer pi points to" 它实际上与 pi[0]
.
相同
pcl
然后使用函数 malloc
指向一个堆分配的内存块,该内存块大到足以容纳 14 个字符加上一个 '\0' 字符(即 15 个字节)(如上所示,在某些时候这个必须释放内存)。
然后使用函数 strcpy
.
将 15 个字符 "Dynamic String[=31=]" 放入该内存中
Is it assigning memory to the variables pi and pcl?
是的malloc
是分配内存给这些指针。
pi
分配的内存等于 sizeof(int)
(可能会有所不同),pcl
分配的内存等于 length of string plus 1
([=15= 加 1) ]).
From first looks, two pointers are initialised, pi and pcl, of type int and char respectively
它们已声明未初始化。
注- Please don't cast return of malloc
行:
pi = (int *) malloc(sizeof(int))
实际上为一个 int 变量分配内存。之后的行将值 35 放入该变量。
行:
pcl = (char *) malloc(strlen("Dynamic String") + 1)
创建一个动态分配的 char 数组(相当于一个字符串)。该数组的大小是字符串的长度 ("Dynamic String") 加一。下一行将字符串:"Dynamic String" 复制到分配的数组中。加一是必需的,因为 c
中的每个字符串都以字符 '[=13=]'
结尾,这是字符串结尾的标志。
malloc
函数在heap(动态内存池)中保留一块内存,returns指向第一个元素的指针那块内存。该内存将保留,直到您调用 free
,或程序退出。
通话中
pi = (int *) malloc(sizeof(int));
malloc
保留一块足够大的内存来存储单个 int
值,并且指向该内存块的指针被分配给 pi
。您不需要转换 malloc
1 的结果,这实际上被认为是不好的做法 2。更好的写法是
pi = malloc( sizeof *pi );
表达式 *pi
的类型为 int
,因此 sizeof *pi
等价于 sizeof (int)
3。使用 sizeof *pi
而不是 sizeof (int)
的优点(以及放弃强制转换)是,如果您更改 pi
的类型(从 int *
到 long *
,例如),您不必在 malloc
调用中更改任何内容;无论 pi
的类型如何,它总是会分配正确数量的内存。少了一个令人头疼的维护问题。
同样,调用
pcl = (char *) malloc(strlen("Dynamic String") + 1);
保留足够的内存来保存 "Dynamic String"
的内容(+1 是字符串终止符所必需的)并将指向该内存的指针分配给 pcl
。同样,最好写成
pcl = malloc( strlen("Dynamic String") + 1 ); // no cast
sizeof (char)
根据定义为 1,因此您不需要在上面的调用中显式 sizeof *pcl
;但是,如果您决定将 pcl
的类型从 char *
更改为 wchar_t *
,最好保留它,尽管您仍然需要更改字符串文字并更改计算长度的方式,因此它不是免维护的。
malloc
调用的一般形式是
T *p = malloc( num_elements * sizeof *p ); // where num_elements > 1
或
T *p;
...
p = malloc( num_elements * sizeof *p );
有一个名为 calloc
的类似函数,它会将分配的内存块清零:
T *p = calloc( num_elements, sizeof *p );
或
T *p;
...
p = calloc( num_elements, sizeof *p );
1。无论如何,在 C 中; C++ 需要强制转换,因为 C++ 不允许 void *
和其他指针类型之间的隐式转换。但是无论如何,您不应该在 C++ 代码中使用 malloc
。
那么,为什么人们仍然将 malloc
的结果转换为 C 语言呢?这在很大程度上是 ANSI 之前的日子(超过四分之一个世纪前)的遗留物,当时 malloc
返回 char *
,如果不强制转换就不能分配给不同的指针类型。 1989 标准引入了 void *
类型,它本质上是一个 "generic" 指针,无需显式转换即可分配给其他指针类型。
2. 在 C89 标准下,如果编译器看到一个函数调用而没有看到该函数的声明,它将假定函数 returns int
。因此,如果您忘记包含 stdlib.h
或在范围内没有 malloc
的声明,编译器将假定它是 returns 一个 int
值并生成机器相应的调用代码。但是,int
和指针类型 不兼容 ,如果您尝试将一个分配给另一个,编译器通常会发出诊断。但是,通过使用强制转换,您可以抑制该诊断,并且稍后您可能 运行 陷入 运行 时间问题。
1999 年的标准取消了函数的隐式 int
类型,因此这不再是真正的问题,但转换仍然是不必要的,并且会导致维护问题。
3、sizeof
是一个运算符,不是函数;仅当操作数是类型名称如 int
或 double
或 struct blah
.
时才需要括号
我正在尝试记录一些代码以提高我对指针的了解和一般的 ANSI C 能力。
...
int static_store = 30;
const char * pcg = "String Literal";
int main()
{
int auto_store = 40;
char auto_string[] = "Auto char Array";
int * pi;
char * pcl;
pi = (int *) malloc(sizeof(int));
*pi = 35;
pcl = (char *) malloc(strlen("Dynamic String") + 1);
strcpy(pcl, "Dynamic String");
...
乍一看,初始化了两个指针,pi和pcl,分别是int和char类型。
但是后面的几行让我很困惑,我不明白发生了什么。我可以看到正在调用 malloc 来分配 int (40) 大小的内存。是给变量pi和pcl分配内存吗?
2 个指针被 delcared(pi
和 pcl
)。在声明时,它们 未 初始化。
pi
然后指向一个堆分配的内存块,该内存块可以容纳 1 个 int(其大小取决于平台,但通常为 4 个字节)分配有函数 maloc
。在某处必须使用函数 free
显式释放此内存 - 不这样做将导致内存泄漏。
然后将 int 值 35 存储在该内存位置。 *pi
可以读作 "what the pointer pi points to" 它实际上与 pi[0]
.
相同
pcl
然后使用函数 malloc
指向一个堆分配的内存块,该内存块大到足以容纳 14 个字符加上一个 '\0' 字符(即 15 个字节)(如上所示,在某些时候这个必须释放内存)。
然后使用函数 strcpy
.
Is it assigning memory to the variables pi and pcl?
是的malloc
是分配内存给这些指针。
pi
分配的内存等于 sizeof(int)
(可能会有所不同),pcl
分配的内存等于 length of string plus 1
([=15= 加 1) ]).
From first looks, two pointers are initialised, pi and pcl, of type int and char respectively
它们已声明未初始化。
注- Please don't cast return of malloc
行:
pi = (int *) malloc(sizeof(int))
实际上为一个 int 变量分配内存。之后的行将值 35 放入该变量。
行:
pcl = (char *) malloc(strlen("Dynamic String") + 1)
创建一个动态分配的 char 数组(相当于一个字符串)。该数组的大小是字符串的长度 ("Dynamic String") 加一。下一行将字符串:"Dynamic String" 复制到分配的数组中。加一是必需的,因为 c
中的每个字符串都以字符 '[=13=]'
结尾,这是字符串结尾的标志。
malloc
函数在heap(动态内存池)中保留一块内存,returns指向第一个元素的指针那块内存。该内存将保留,直到您调用 free
,或程序退出。
通话中
pi = (int *) malloc(sizeof(int));
malloc
保留一块足够大的内存来存储单个 int
值,并且指向该内存块的指针被分配给 pi
。您不需要转换 malloc
1 的结果,这实际上被认为是不好的做法 2。更好的写法是
pi = malloc( sizeof *pi );
表达式 *pi
的类型为 int
,因此 sizeof *pi
等价于 sizeof (int)
3。使用 sizeof *pi
而不是 sizeof (int)
的优点(以及放弃强制转换)是,如果您更改 pi
的类型(从 int *
到 long *
,例如),您不必在 malloc
调用中更改任何内容;无论 pi
的类型如何,它总是会分配正确数量的内存。少了一个令人头疼的维护问题。
同样,调用
pcl = (char *) malloc(strlen("Dynamic String") + 1);
保留足够的内存来保存 "Dynamic String"
的内容(+1 是字符串终止符所必需的)并将指向该内存的指针分配给 pcl
。同样,最好写成
pcl = malloc( strlen("Dynamic String") + 1 ); // no cast
sizeof (char)
根据定义为 1,因此您不需要在上面的调用中显式 sizeof *pcl
;但是,如果您决定将 pcl
的类型从 char *
更改为 wchar_t *
,最好保留它,尽管您仍然需要更改字符串文字并更改计算长度的方式,因此它不是免维护的。
malloc
调用的一般形式是
T *p = malloc( num_elements * sizeof *p ); // where num_elements > 1
或
T *p;
...
p = malloc( num_elements * sizeof *p );
有一个名为 calloc
的类似函数,它会将分配的内存块清零:
T *p = calloc( num_elements, sizeof *p );
或
T *p;
...
p = calloc( num_elements, sizeof *p );
1。无论如何,在 C 中; C++ 需要强制转换,因为 C++ 不允许
void *
和其他指针类型之间的隐式转换。但是无论如何,您不应该在 C++ 代码中使用 malloc
。 那么,为什么人们仍然将
malloc
的结果转换为 C 语言呢?这在很大程度上是 ANSI 之前的日子(超过四分之一个世纪前)的遗留物,当时 malloc
返回 char *
,如果不强制转换就不能分配给不同的指针类型。 1989 标准引入了 void *
类型,它本质上是一个 "generic" 指针,无需显式转换即可分配给其他指针类型。2. 在 C89 标准下,如果编译器看到一个函数调用而没有看到该函数的声明,它将假定函数 returns
int
。因此,如果您忘记包含 stdlib.h
或在范围内没有 malloc
的声明,编译器将假定它是 returns 一个 int
值并生成机器相应的调用代码。但是,int
和指针类型 不兼容 ,如果您尝试将一个分配给另一个,编译器通常会发出诊断。但是,通过使用强制转换,您可以抑制该诊断,并且稍后您可能 运行 陷入 运行 时间问题。1999 年的标准取消了函数的隐式
int
类型,因此这不再是真正的问题,但转换仍然是不必要的,并且会导致维护问题。 3、
sizeof
是一个运算符,不是函数;仅当操作数是类型名称如 int
或 double
或 struct blah
.时才需要括号