Lab0 C Programming Lab

Lab0 C Programming Lab

一、关于实验环境的配置

下载地址15-213/14-513/15-513: Introduction to Computer Systems / Schedule Fall 2021 (cmu.edu)

Lab0 C Programming Lab(CMU)(CSAPP深入理解计算机系统)_虚拟机cprogramminglab-CSDN博客

环境我是用的wsl,用vscode远程链接,搭环境网上又很多帖子,我就不写了

make format
make test

二、内容

1.结构体

typedef struct list_ele {

  char *value;

  struct list_ele *next;

} list_ele_t;


typedef struct {

  list_ele_t *head;

  list_ele_t *tail;

  size_t size;

} queue_t;

2.函数实现

queue_t *queue_new(void) {
    queue_t *q = (queue_t *)malloc(sizeof(queue_t));
    /* What if malloc returned NULL? */
    if (q == NULL)
        return NULL;
    q->head = NULL;
    q->tail = NULL;
    q->size = 0;
    return q;
}
void queue_free(queue_t *q) {
    /* How about freeing the list elements and the strings? */
    if (q == NULL)
        return;
    for (size_t i = 0; i < (q->size); i++) {
        list_ele_t *tmp = q->head;
        q->head = q->head->next;
        free(tmp->value);
        free(tmp);
    }
    /* Free queue structure */
    free(q);
    q = NULL;
}
bool queue_insert_head(queue_t *q, const char *s) {
    if (q == NULL)
        return false;

    list_ele_t *newh;
    /* What should you do if the q is NULL? */
    newh = (list_ele_t *)malloc(sizeof(list_ele_t));
    if (newh == NULL)
        return false;
    /* Don't forget to allocate space for the string and copy it */
    newh->value = (char *)malloc(sizeof(char) * (strlen(s) + 1));
    if (newh->value == NULL) {
        free(newh);
        return false;
    }
    strcpy(newh->value, s);
    /* What if either call to malloc returns NULL? */
    if (q->size == 0) {
        q->head = newh;
        q->tail = newh;
        q->tail->next = NULL;
    } else {
        newh->next = q->head;
        q->head = newh;
    }

    q->size++;
    return true;
}
bool queue_insert_tail(queue_t *q, const char *s) {
    if (q == NULL)
        return false;
    /* You need to write the complete code for this function */
    list_ele_t *newh = (list_ele_t *)malloc(sizeof(list_ele_t));
    if (newh == NULL)
        return false;
    newh->value = (char *)malloc(sizeof(char) * (strlen(s) + 1));
    if (newh->value == NULL) {
        free(newh);
        return false;
    }
    strcpy(newh->value, s);
    newh->next = NULL;
    /* Remember: It should operate in O(1) time */
    if (q->tail == NULL) {
        q->head = newh;
        q->tail = newh;
    } else {
        q->tail->next = newh;
        q->tail = newh;
    }

    q->size++;
    return true;
}
bool queue_remove_head(queue_t *q, char *buf, size_t bufsize) {
    /* You need to fix up this code. */
    if (q == NULL || q->size == 0)
        return false;

    // get headNode
    list_ele_t *tmp = q->head;
    q->head = q->head->next;

    if (buf != NULL) {
        strncpy(buf, tmp->value, bufsize - 1);
        buf[bufsize - 1] = '\0';
    }

    free(tmp->value);
    free(tmp);

    q->size--;
    return true;
}
size_t queue_size(queue_t *q) {
    /* You need to write the code for this function */
    /* Remember: It should operate in O(1) time */
    if (q == NULL)
        return 0;

    return q->size;
}
void queue_reverse(queue_t *q) {
    /* You need to write the code for this function */
    if (q == NULL || q->size == 0)
        return;
    list_ele_t *oldh = q->head;
    list_ele_t *oldt = q->tail;

    list_ele_t *t1 = q->head;
    list_ele_t *t2 = t1->next;
    t1->next = NULL;
    while (t2 != NULL) {
        list_ele_t *tmp = t2->next;
        t2->next = t1;
        t1 = t2;
        t2 = tmp;
    }

    q->head = oldt;
    q->tail = oldh;
}

三、总结

  1. malloc 和 delete动态内存管理

    在堆上申请一块指定大小的内存,申请失败则会返回NULL,若成功记得初始化

    delete成功后,要将指针设为NULL

  2. 内存泄露

    struct Node
    {
    	char *a;
    	char *b;
    }
    一个指针p指向该结构体,结构体有两个指针a、b分别指向char数组,如果直接free(p)会发生什么。
    答:如果直接使用free(p)来释放指针p指向的结构体,那么只会释放结构体本身所占用的内存空间,也就是两个char指针本身所占内存,并不会释放结构体内部指针a和b所指向的内存空间。
    
    这样会导致问题:
    ①结构体内部指针a和b所指向的内存空间没有被释放,造成内存泄漏。这会导致程序运行时占用的内存越来越多,最终可能耗尽系统资源。
    ②在之后访问指针a和b时,由于这些指针已经无效,可能会导致程序崩溃或出现未定义行为。
    正确的做法是,在释放指针p之前,先释放指针a和b所指向的内存空间,然后再调用free(p)释放结构体本身所占用的内存空间。可以使用free(a)和free(b)来释放指针a和b所指向的内存空间。
    
    示例代码:
    free(a);
    free(b);
    free(p);
    
  3. 指针悬空和野指针

    指针悬空和野指针是两个不同的概念,但都与指针使用错误相关。

    而程序判断一个指针是否合法,通常都是使用if语句测试该指针是否为NULL来判断

    指针悬空(Dangling Pointer):指针悬空是指在程序中存在指向已经释放的内存区域的指针。通常,在释放内存后,应将指针设置为 NULL,以避免指针悬空。如果继续使用指向已释放内存的指针,可能会导致未定义的行为,如访问无效的内存地址,导致程序崩溃或产生意料之外的结果。
    int* p = new int(10);
    delete p;
    p = NULL;
    int value = *p; // 悬空指针访问,可能导致未定义的行为
    
    野指针(Wild Pointer):野指针是指没有被初始化或者指向无效内存地址的指针。野指针通常是由于声明指针但未给其分配有效内存,或者在释放内存后未将指针设置为 NULL 而继续使用。野指针可能会导致程序崩溃、数据损坏或其他严重后果。
    int* p;
    *p = 10; // 未初始化的指针,产生野指针
    
  4. 指针p是malloc的,现在q指向p,我free(q)然后q=NULL

    虽然你对 q 进行了操作(释放内存并设置为 NULL),但这并不会影响 p 的值。p 仍然保持着之前分配的内存地址,但这是一个关键问题:尽管 p 的值没有改变,p 现在是一个悬挂指针,因为它指向的内存已经被释放。此时,通过 p 访问该内存也是未定义行为。
    
  5. free(NULL)没问题,但变成NULL后就无法再p->next了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值