声明一个字符数组VS动态地将空间分配给C中的字符数组

时间:2017-02-18 18:04:54

标签: c algorithm pointers data-structures malloc

int main(){
    int i = 0;
    while(i < 2){
        char str[10];
        printf("%p\n", str); //outputs same address both the times
        i++;
    }

    i = 0;

    while(i<2){
        char *str;
        str = (char*)malloc(10*sizeof(char));
        printf("%p\n", str); //outputs two different addresses
        i++;
    }

}

在上面的代码中,为什么在循环中声明相同的字符数组会给出相同的地址,尽管变量被声明两次不同的时间。所以根据我的理解,它应该为它分配新的内存。但它每次都返回相同的地址。

在动态分配内存的第二个中,它返回两个不同的地址,这是可以理解的,因为malloc每次都会为我找到新的连续内存块。

但是为什么它会在第一种情况下打印相同的地址?

2 个答案:

答案 0 :(得分:7)

在您的第一个示例中,char str[10];是仅在{ }范围内有效的局部变量。范围结束后,变量被破坏并且内存被“释放”。下一个位置可以在同一个空间中,因为它是空的并且可用。

在第二个示例中,您使用malloc ...在您致电free(或程序结束)之前,内存不会自动释放。

答案 1 :(得分:3)

在第一种情况下,char str[10]在堆栈上分配一次,并且在程序停留在同一块{}时保持指向它的指针。它没有被分配两次,即使你正在循环。并不是内存在神话}的末尾变得“可用”,然后被“重新分配”,因为它再次可用。查看为第一部分生成的LLVM ir代码:

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  %i = alloca i32, align 4

  ; actuall allocation of str as a 10 byte value
  ; occurs OUTSIDE the looping labels
  ; and deallocation also occurs outside the looping
  ; label (see label 10) 
  %str = alloca [10 x i8], align 1


  %str1 = alloca i8*, align 8
  store i32 0, i32* %1
  store i32 0, i32* %i, align 4
  br label %2

; this is the opening {
; <label>:2                                       ; preds = %5, %0
  %3 = load i32* %i, align 4
  %4 = icmp slt i32 %3, 2

; LOOP breaks out on the condition matching i>2
  br i1 %4, label %5, label %10


; <label>:5                                       ; preds = %2
  %6 = getelementptr inbounds [10 x i8]* %str, i32 0, i32 0
  %7 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i8* %6)
  %8 = load i32* %i, align 4
  %9 = add nsw i32 %8, 1
  store i32 %9, i32* %i, align 4

  ; LOOP back to label %2 which does NOT include the
  ; original allocation logic between here and there logic 
  ; this is the closing } 
  br label %2



; DEALLOCATION occurs here

; <label>:10                                      ; preds = %2
  store i32 0, i32* %i, align 4
  br label %11

这是使用gcc

的相同代码

使用gcc -fdump-tree-all查看不同的解释阶段:

GIMPLE

main ()
{
  int i;

  i = 0;
  goto <D.2181>;
  <D.2180>:
  {
    char str[10];

    try
      {
        printf ("%p\n", &str);
        i = i + 1;
      }
    finally
      {
        str = {CLOBBER};
      }
  }
  <D.2181>:
  if (i <= 1) goto <D.2180>; else goto <D.2182>;
  <D.2182>:
  i = 0;
  goto <D.2186>;
  <D.2185>:
  {
    char * str;
    extern void * malloc (long unsigned int);

    str = malloc (10);
    printf ("%p\n", str);
    i = i + 1;
  }
  <D.2186>:
  if (i <= 1) goto <D.2185>; else goto <D.2187>;
  <D.2187>:
}

原始

;; Function main (null)
;; enabled by -tree-original


{
  int i = 0;

    int i = 0;
  goto <D.2181>;
  <D.2180>:;
  {
    char str[10];

        char str[10];
    printf ((const char * restrict) "%p\n", (char *) &str);
    i++ ;
  }
  <D.2181>:;
  if (i <= 1) goto <D.2180>; else goto <D.2182>;
  <D.2182>:;
  i = 0;
  goto <D.2186>;
  <D.2185>:;
  {
    char * str;
    extern void * malloc (long unsigned int);

        char * str;
    str = (char *) malloc (10);
    printf ((const char * restrict) "%p\n", str);
    i++ ;
  }
  <D.2186>:;
  if (i <= 1) goto <D.2185>; else goto <D.2187>;
  <D.2187>:;
}