这里回顾第14章,本章介绍了插叙:内存操作API。

书籍介绍:

学习资料:

参考资料:

第14 章 插叙:内存操作API

内容回顾

关键概念

  • 内存类型:

    • 栈内存,由编译器管理,称为自动内存
    • 堆内存,有程序员显式申请和释放
  • 易错的例子

    代码1:

    int *x = malloc(10 * sizeof(int));
    printf("%d\n", sizeof(x));

    结果:

    4

    代码2:

    int x[10];
    printf("%d\n", sizeof(x));

    结果:

    40
  • 一些错误

    • 段错误(segmentation fault)

      char *src = "hello";
      char *dst; // oops! unallocated
      strcpy(dst, src); // segfault and die
    • 缓冲区溢出(buffer overflow)

      char *src = "hello";
      char *dst = (char *) malloc(strlen(src)); // too small!
      strcpy(dst, src); // work properly
  • 常见错误:

    • 忘记分配内存
    • 没有分配足够的内存
    • 忘记初始化分配的内存
    • 忘记释放内存
    • 在用完之前释放内存
    • 反复释放内存
    • 错误地调用free()

作业

1

例子:

#include <stdio.h>

int main() {
    int a[3];
    int *ptr = a;
    ptr = NULL;
    free(ptr);

    return 0;
}

测试:

╰─○ ./p1           
free(): invalid pointer
[1]    1073 abort      ./p1

2

编译:

gcc -o p2 p1.c -g -Wall
p1.c: In function ‘main’:
p1.c:7:5: warning: implicit declaration of function ‘free’ [-Wimplicit-function-declaration]
     free(a);
     ^~~~
p1.c:7:5: warning: incompatible implicit declaration of built-in function ‘free’
p1.c:7:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘free’
p1.c:2:1:
+#include <stdlib.h>
 
p1.c:7:5:
     free(a);
     ^~~~
p1.c:5:10: warning: variable ‘ptr’ set but not used [-Wunused-but-set-variable]
     int *ptr = a;
          ^~~
p1.c:7:5: warning: attempt to free a non-heap object ‘a’ [-Wfree-nonheap-object]
     free(a);
     ^~~~~~~

测试:

╰─○ gdb p2  
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from p2...done.
(gdb) run
Starting program: /home/ostep/hw/14/p2 
free(): invalid pointer

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.

报错含义:

3

运行:

╰─○ valgrind --leak-check=yes ./p2
==1371== Memcheck, a memory error detector
==1371== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1371== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==1371== Command: ./p2
==1371== 
==1371== Invalid free() / delete / delete[] / realloc()
==1371==    at 0x4C32D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1371==    by 0x1086B7: main (p1.c:7)
==1371==  Address 0x1ffefff60c is on thread 1's stack
==1371==  in frame #1, created by main (p1.c:3)
==1371== 
==1371== 
==1371== HEAP SUMMARY:
==1371==     in use at exit: 0 bytes in 0 blocks
==1371==   total heap usage: 0 allocs, 1 frees, 0 bytes allocated
==1371== 
==1371== All heap blocks were freed -- no leaks are possible
==1371== 
==1371== For counts of detected and suppressed errors, rerun with: -v
==1371== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

4

代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr;
    ptr = malloc(10 * sizeof(int));

    return 0;
}

测试运行:

╰─○ make p4 && ./p4
gcc -o p4 p4.c -Wall
p4.c: In function ‘main’:
p4.c:5:10: warning: variable ‘ptr’ set but not used [-Wunused-but-set-variable]
     int *ptr;
          ^~~

gdb测试:

╰─○ gdb p4
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from p4...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/ostep/hw/14/p4 
[Inferior 1 (process 1785) exited normally]
(gdb) 

valgrind测试:

╰─○ valgrind --leak-check=yes ./p4
==1918== Memcheck, a memory error detector
==1918== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1918== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==1918== Command: ./p4
==1918== 
==1918== 
==1918== HEAP SUMMARY:
==1918==     in use at exit: 40 bytes in 1 blocks
==1918==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==1918== 
==1918== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1918==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1918==    by 0x108636: main (in /home/ostep/hw/14/p4)
==1918== 
==1918== LEAK SUMMARY:
==1918==    definitely lost: 40 bytes in 1 blocks
==1918==    indirectly lost: 0 bytes in 0 blocks
==1918==      possibly lost: 0 bytes in 0 blocks
==1918==    still reachable: 0 bytes in 0 blocks
==1918==         suppressed: 0 bytes in 0 blocks
==1918== 
==1918== For counts of detected and suppressed errors, rerun with: -v
==1918== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

5

代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr;
    ptr = malloc(100 * sizeof(int));
    ptr[100] = 0;
    free(ptr);

    return 0;
}

编译运行:

╰─○ make p5 && ./p5
gcc -o p5 p5.c -Wall

valgrind:

╰─○ valgrind --leak-check=yes ./p5
==2290== Memcheck, a memory error detector
==2290== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2290== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2290== Command: ./p5
==2290== 
==2290== Invalid write of size 4
==2290==    at 0x108685: main (in /home/ostep/hw/14/p5)
==2290==  Address 0x522f1d0 is 0 bytes after a block of size 400 alloc'd
==2290==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2290==    by 0x108676: main (in /home/ostep/hw/14/p5)
==2290== 
==2290== 
==2290== HEAP SUMMARY:
==2290==     in use at exit: 0 bytes in 0 blocks
==2290==   total heap usage: 1 allocs, 1 frees, 400 bytes allocated
==2290== 
==2290== All heap blocks were freed -- no leaks are possible
==2290== 
==2290== For counts of detected and suppressed errors, rerun with: -v
==2290== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

没有报错。

6

代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr;
    ptr = malloc(100 * sizeof(int));
    free(ptr);

    printf("%d\n", ptr[1]);

    return 0;
}

编译运行:

╰─○ make p6 && ./p6
gcc -o p6 p6.c -Wall
0

valgrind测试:

╰─○ valgrind --leak-check=yes ./p6
==2492== Memcheck, a memory error detector
==2492== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2492== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2492== Command: ./p6
==2492== 
==2492== Invalid read of size 4
==2492==    at 0x1086DF: main (in /home/ostep/hw/14/p6)
==2492==  Address 0x522f044 is 4 bytes inside a block of size 400 free'd
==2492==    at 0x4C32D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2492==    by 0x1086D6: main (in /home/ostep/hw/14/p6)
==2492==  Block was alloc'd at
==2492==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2492==    by 0x1086C6: main (in /home/ostep/hw/14/p6)
==2492== 
0
==2492== 
==2492== HEAP SUMMARY:
==2492==     in use at exit: 0 bytes in 0 blocks
==2492==   total heap usage: 2 allocs, 2 frees, 1,424 bytes allocated
==2492== 
==2492== All heap blocks were freed -- no leaks are possible
==2492== 
==2492== For counts of detected and suppressed errors, rerun with: -v
==2492== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

7

参考:

题目的含义是free数组中某个位置:

代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr;
    ptr = malloc(100 * sizeof(int));
    free(&ptr[20]);

    return 0;
}

编译运行:

╰─○ make p7 && ./p7  
gcc -o p7 p7.c -Wall
free(): invalid pointer
[1]    1840 abort      ./p7

测试:

╰─○ valgrind --leak-check=yes ./p7
==2903== Memcheck, a memory error detector
==2903== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2903== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2903== Command: ./p7
==2903== 
==2903== Invalid free() / delete / delete[] / realloc()
==2903==    at 0x4C32D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2903==    by 0x10868A: main (in /home/ostep/hw/14/p7)
==2903==  Address 0x522f090 is 80 bytes inside a block of size 400 alloc'd
==2903==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2903==    by 0x108676: main (in /home/ostep/hw/14/p7)
==2903== 
==2903== 
==2903== HEAP SUMMARY:
==2903==     in use at exit: 400 bytes in 1 blocks
==2903==   total heap usage: 1 allocs, 1 frees, 400 bytes allocated
==2903== 
==2903== 400 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2903==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2903==    by 0x108676: main (in /home/ostep/hw/14/p7)
==2903== 
==2903== LEAK SUMMARY:
==2903==    definitely lost: 400 bytes in 1 blocks
==2903==    indirectly lost: 0 bytes in 0 blocks
==2903==      possibly lost: 0 bytes in 0 blocks
==2903==    still reachable: 0 bytes in 0 blocks
==2903==         suppressed: 0 bytes in 0 blocks
==2903== 
==2903== For counts of detected and suppressed errors, rerun with: -v
==2903== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

8

代码:

#include <stdio.h>
#include <stdlib.h>

const int N = 1000;
typedef struct Vector Vector;

struct Vector {
    // 当前大小
    int l;
    // 当前索引
    int i;
    int* ptr;
    // 初始化
};

Vector* InitVector(int n) {
    Vector* vec = malloc(sizeof(Vector));
    vec->ptr = (int *)malloc(n * sizeof(int));
    vec->i = 0;
    vec->l = n;

    return vec;
}

void FreeVector(Vector* vec) {
    free(vec->ptr);
    free(vec);
}

int VectorPush(Vector* vec, int d) {
    if (vec->i >= vec->l) {
        printf("Before realloc, size is %ld bytes!\n", vec->l * sizeof(int));
        vec->l *= 2;
        vec->ptr = (int *)realloc(vec->ptr, vec->l * sizeof(int));
        if (vec->ptr == NULL) {
            printf("Realloc fail!\n");
            return -1;
        }
        printf("After realloc, size is %ld bytes!\n", vec->l * sizeof(int));
    }
    vec->ptr[vec->i] = d;
    vec->i += 1;

    return 1;
}

void VectorPrint(Vector* vec) {
    printf("%d", vec->ptr[0]);
    for (int i = 1; i < vec->i; i++) {
        printf(" %d", vec->ptr[i]);
    }
    printf("\n");
}

int main() {
    int n = 5;
    Vector* vec = InitVector(n);
    for (int i = 0; i < n; i++) {
        VectorPush(vec, i);
    }

    VectorPrint(vec);
    VectorPush(vec, n);
    VectorPrint(vec);
    FreeVector(vec);

    return 0;
}

编译运行:

╰─○ make p8 && ./p8
gcc -o p8 p8.c -Wall
0 1 2 3 4
Before realloc, size is 20 bytes!
After realloc, size is 40 bytes!
0 1 2 3 4 5

测试:

╰─○ valgrind --leak-check=yes ./p8
==4044== Memcheck, a memory error detector
==4044== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4044== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4044== Command: ./p8
==4044== 
0 1 2 3 4
Before realloc, size is 20 bytes!
After realloc, size is 40 bytes!
0 1 2 3 4 5
==4044== 
==4044== HEAP SUMMARY:
==4044==     in use at exit: 0 bytes in 0 blocks
==4044==   total heap usage: 4 allocs, 4 frees, 1,100 bytes allocated
==4044== 
==4044== All heap blocks were freed -- no leaks are possible
==4044== 
==4044== For counts of detected and suppressed errors, rerun with: -v
==4044== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

9

略过。