C:指针题
C: pointer questions
关于以下代码的两个问题:
有和没有malloc()
语句有什么区别:
p = (char *) malloc (20 * sizeof(char) );
仅仅是内存位置的不同吗?指针变量 'p
' 在没有该语句的情况下处于 STACK 中,而在具有该语句的 HEAP 中?
为什么语句是
printf("%s\n", p);
不是
printf("%s\n", *p);
#include <stdlib.h>
#include <stdio.h>
int main () {
char movie[] = "forrest gump";
char *p;
p = (char *) malloc (20 * sizeof(char) );
p = movie;
printf("%p\n", p);
printf("%p\n", movie);
printf("%s\n", p); // to print "forrest gump"
free(p);
return 0;
}
大多数情况下,是的。 malloc
分配堆 space 和 returns 一个指向它的指针。当函数进入时,stack space 被分配给任何局部变量。在这种情况下,数组 movie
为 13 个字节("forrest gump" 带有空终止符,可能更多取决于对齐问题和字符宽度)。 movie
将使用指定的数据进行初始化。如果字符串更长,它将从编译器设置的常量数据中的副本复制(直到最近十年左右,它会对任何字符串这样做,但现在看来至少有一些编译器初始化直接使用机器代码的短字符串)。还有space为指针p
分配在栈上
printf
将 %s
的行为定义为期待指针。将 'string' 放在堆栈上(而不是指向它的指针)会使语言的实现严重复杂化,因为它们的大小是可变的。字符串在 C 中不是特殊的结构,因为它们在许多其他语言中都是如此。在 C 中,它们只是一个以 null
或零字节结尾的字符数组(只有字符串库函数关心这一点——编译器不关心,除了可能的错误检查)。
问题 1
添加行号注释的代码:
char movie[] = "forrest gump"; // 1
char *p; // 2
p = (char *) malloc (20 * sizeof(char) ); // 3
p = movie; // 4
printf("%p\n", p); // 5
printf("%p\n", movie); // 6
printf("%s\n", p); // to print "forrest gump" // 7
free(p); // 8
我会忽略 malloc()
中的 return 值未被检查,并且我不会被 malloc()
中的 return 值强制转换,只要如果您省略 malloc()
的声明,您的编译器会告诉您——但有很多人不同意这一点。 * sizeof(char)
不是必需的,最好写成 * sizeof(*p)
.
代码存在内存泄漏,并且由于内存泄漏而表现出未定义的行为。
第 1 行没问题。第 2 行同样很好,尽管可以通过将它与第 3 行组合来初始化变量。
第 3 行在这种情况下是安全的,但分配的固定大小在其他情况下会成为问题。
第 4 行是一个主要问题。这是泄漏。您刚刚践踏了 return 由 malloc()
编辑的内存的唯一指针,因此内存不可挽回地丢失了。诚然,这个程序很快就会退出(如果它没有先崩溃的话),但总的来说,这很糟糕。你应该写:
strcpy(p, movie);
或者也许:
memmove(p, movie, sizeof(movie));
第 5 行将打印存储在 p
中的地址。正如所写,这是 movie
的地址,因为第 4 行中的赋值。可以说,它应该用强制转换来编写,因为 %p
格式说明符采用 void *
:
printf("%p\n", (void *)p);
在实践中,当 p
是 char *
时,您将无处不在。我学会了在一台机器上编程(在有 C 标准之前的日子里),其中 char *
地址的位表示与同一内存位置的 anything_bigger *
地址不同。在这样的机器上,如果代码正在处理 struct Something *
甚至 int *
,则需要强制转换为 void *
。
第 6 行产生与第 5 行相同的输出,并具有相同的注意事项。
第7行没问题,打印出p
指向的数据,也是movie
指向的数据。
第 8 行是调用未定义行为的地方。由于第 4 行中的分配,您试图释放未分配的 space,这是一场严重的灾难。它通常会导致崩溃;这绝不是一个好主意。
代码应该写得似是而非:
char movie[] = "forrest gump";
char *p = malloc(sizeof(movie)); // or: char *p = malloc(strlen(movie) + 1);
if (p != 0)
{
strcpy(p, movie);
printf("%p\n", p);
printf("%p\n", movie);
printf("%s\n", p);
free(p);
}
问题 2
您的问题 2 是关于:
printf("%s\n", p);
printf("%s\n", *p);
第一个是正确的。 p
是一个 char *
,而 %s
转换规范需要一个 char *
。第二个不正确,因为 *p
是 char
,但 %s
期望 char *
。相反,它获取一个小整数(如果您的代码集基于 ASCII,则为 102)并尝试将其视为地址。这是行不通的;它通常会导致崩溃,因为整个第一页内存(1 KiB 或 4 KiB)通常被映射为无效。
您可以使用:
printf("%c\n", *p);
这将打印 f
.
关于以下代码的两个问题:
有和没有
malloc()
语句有什么区别:p = (char *) malloc (20 * sizeof(char) );
仅仅是内存位置的不同吗?指针变量 '
p
' 在没有该语句的情况下处于 STACK 中,而在具有该语句的 HEAP 中?为什么语句是
printf("%s\n", p);
不是
printf("%s\n", *p);
#include <stdlib.h>
#include <stdio.h>
int main () {
char movie[] = "forrest gump";
char *p;
p = (char *) malloc (20 * sizeof(char) );
p = movie;
printf("%p\n", p);
printf("%p\n", movie);
printf("%s\n", p); // to print "forrest gump"
free(p);
return 0;
}
大多数情况下,是的。
malloc
分配堆 space 和 returns 一个指向它的指针。当函数进入时,stack space 被分配给任何局部变量。在这种情况下,数组movie
为 13 个字节("forrest gump" 带有空终止符,可能更多取决于对齐问题和字符宽度)。movie
将使用指定的数据进行初始化。如果字符串更长,它将从编译器设置的常量数据中的副本复制(直到最近十年左右,它会对任何字符串这样做,但现在看来至少有一些编译器初始化直接使用机器代码的短字符串)。还有space为指针p
分配在栈上printf
将%s
的行为定义为期待指针。将 'string' 放在堆栈上(而不是指向它的指针)会使语言的实现严重复杂化,因为它们的大小是可变的。字符串在 C 中不是特殊的结构,因为它们在许多其他语言中都是如此。在 C 中,它们只是一个以null
或零字节结尾的字符数组(只有字符串库函数关心这一点——编译器不关心,除了可能的错误检查)。
问题 1
添加行号注释的代码:
char movie[] = "forrest gump"; // 1
char *p; // 2
p = (char *) malloc (20 * sizeof(char) ); // 3
p = movie; // 4
printf("%p\n", p); // 5
printf("%p\n", movie); // 6
printf("%s\n", p); // to print "forrest gump" // 7
free(p); // 8
我会忽略 malloc()
中的 return 值未被检查,并且我不会被 malloc()
中的 return 值强制转换,只要如果您省略 malloc()
的声明,您的编译器会告诉您——但有很多人不同意这一点。 * sizeof(char)
不是必需的,最好写成 * sizeof(*p)
.
代码存在内存泄漏,并且由于内存泄漏而表现出未定义的行为。
第 1 行没问题。第 2 行同样很好,尽管可以通过将它与第 3 行组合来初始化变量。
第 3 行在这种情况下是安全的,但分配的固定大小在其他情况下会成为问题。
第 4 行是一个主要问题。这是泄漏。您刚刚践踏了 return 由 malloc()
编辑的内存的唯一指针,因此内存不可挽回地丢失了。诚然,这个程序很快就会退出(如果它没有先崩溃的话),但总的来说,这很糟糕。你应该写:
strcpy(p, movie);
或者也许:
memmove(p, movie, sizeof(movie));
第 5 行将打印存储在 p
中的地址。正如所写,这是 movie
的地址,因为第 4 行中的赋值。可以说,它应该用强制转换来编写,因为 %p
格式说明符采用 void *
:
printf("%p\n", (void *)p);
在实践中,当 p
是 char *
时,您将无处不在。我学会了在一台机器上编程(在有 C 标准之前的日子里),其中 char *
地址的位表示与同一内存位置的 anything_bigger *
地址不同。在这样的机器上,如果代码正在处理 struct Something *
甚至 int *
,则需要强制转换为 void *
。
第 6 行产生与第 5 行相同的输出,并具有相同的注意事项。
第7行没问题,打印出p
指向的数据,也是movie
指向的数据。
第 8 行是调用未定义行为的地方。由于第 4 行中的分配,您试图释放未分配的 space,这是一场严重的灾难。它通常会导致崩溃;这绝不是一个好主意。
代码应该写得似是而非:
char movie[] = "forrest gump";
char *p = malloc(sizeof(movie)); // or: char *p = malloc(strlen(movie) + 1);
if (p != 0)
{
strcpy(p, movie);
printf("%p\n", p);
printf("%p\n", movie);
printf("%s\n", p);
free(p);
}
问题 2
您的问题 2 是关于:
printf("%s\n", p);
printf("%s\n", *p);
第一个是正确的。 p
是一个 char *
,而 %s
转换规范需要一个 char *
。第二个不正确,因为 *p
是 char
,但 %s
期望 char *
。相反,它获取一个小整数(如果您的代码集基于 ASCII,则为 102)并尝试将其视为地址。这是行不通的;它通常会导致崩溃,因为整个第一页内存(1 KiB 或 4 KiB)通常被映射为无效。
您可以使用:
printf("%c\n", *p);
这将打印 f
.