C:指针问题

时间:2015-01-18 05:11:37

标签: c pointers

关于以下代码的两个问题:

  1. 有和没有malloc()声明之间有什么区别:

    p = (char *) malloc (20 * sizeof(char) );
    

    这只是内存位置的差异吗?指针变量' p'在没有该声明的STACK中,在HEAP中是否有该声明?

  2. 为什么声明是

    printf("%s\n", p);
    

    不是

    printf("%s\n", *p);
    

  3. #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;
    }
    

2 个答案:

答案 0 :(得分:5)

问题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()的返回值未被检查,并且只要您的编译器告知您malloc()的返回值,我就不会对其进行分阶段处理你省略了malloc()的声明 - 但是有很多人不同意这一点。 * sizeof(char)不是必需的,可能更好地写为* sizeof(*p)

代码存在内存泄漏,并且由于内存泄漏而显示未定义的行为。

第1行很好。第2行同样很好,但可以通过将变量与第3行组合来初始化变量。

第3行在这种情况下是安全的,但是在其他情况下,分配的固定大小将是一个问题。

第4行是一个主要问题。这是泄漏。您只是践踏了malloc()返回的内存的唯一指针,因此内存不可避免地丢失了。当然,这个程序将很快退出(如果它不首先崩溃),但总的来说,这很糟糕。你应该写:

strcpy(p, movie);

或者也许:

memmove(p, movie, sizeof(movie));

第5行将打印存储在p中的地址。如上所述,由于第4行中的赋值,它是movie的地址。可以说,它应该使用强制转换编写,因为%p格式说明符需要void *

printf("%p\n", (void *)p);

在实践中,当pchar *时,您就会随处可见。我学会了在机器上编程(在有C标准的前几天),其中char *地址的位表示与同一存储位置的anything_bigger *地址不同。在这样的计算机上,如果代码处理struct Something *甚至是int *,则需要转换为void *

第6行产生与第5行相同的输出,并且具有相同的警告。

第7行很好,打印出p指向的数据,这也是movie指向的数据。

第8行是调用未定义行为的地方。由于第4行的分配,你试图释放未分配的空间,这是一场严重的灾难。它经常会导致崩溃;这绝不是一个好主意。

代码应合理地阅读:

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);

第一个是正确的。 pchar *%s转换规范需要char *。第二个不正确,因为*pchar,但%s需要char *。相反,它会获得一个小整数(如果您的代码集基于ASCII,则为102)并尝试将其视为地址。这不起作用;它通常会导致崩溃,因为整个第一页内存(1 KiB或4 KiB)通常被映射为无效。

您可以使用:

printf("%c\n", *p);

会打印f

答案 1 :(得分:0)

  1. 大多数情况下,是的。 malloc分配堆空间并返回指向它的指针。当函数进入时,为任何局部变量分配堆栈空间。在这种情况下,对于数组movie,这是13个字节(“forrest gump”具有空终止符,可能更多取决于对齐问题和字符宽度)。将使用指定的数据初始化movie。如果字符串更长,它将从编译器设置的常量数据中的副本中复制(直到过去十年左右,它会用任何字符串完成,但是现在似乎至少有一些编译器初始化短字符串直接与机器代码)。在堆栈上分配了指针p的空间。

  2. printf%s的行为定义为期望指针。在堆栈上放置一个“字符串”(而不是指向它的指针)会使语言的实现变得非常复杂,因为它们的大小可变。字符串不是C中的特殊构造,因为它们在许多其他语言中。在C中,它们只是一个由null或零字节终止的字符数组(只有字符串库函数关心它 - 编译器没有,除了可能用于错误检查)。