לדלג לתוכן

שפת C/ניהול זיכרון דינאמי/תרגילים

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי

מחיקה בעייתית של חוליה מרשימה מקושרת

[עריכה]

להלן דרך למחיקת חוליה המשתמשת בפחות משתנים מהגרסה שראינו:

const int d = list->head->data;

free(head);

head = l->next;

מה בעייתי בקוד זה?

הפתרון

שיחררנו את הזכרון המוקצה ל־head אך נשארנו עם זכרון שמוקצה ל־data מבלי לדעת למעשה היכן הוא, ובכך איבדנו את היכולת לשחרר את הזיכרון שלו, ותיווצר לנו דליפת זכרון.


שימוש ברשימה מקושרת לקליטת מספרים והדפסתם באותו סדר

[עריכה]

בשימוש בקליטת והפיכת מספרים, ראינו כיצד להשתמש ברשימה מקושרת כדי לקלוט מספרים ולשומרם בסדר הפוך. שנה את התוכנית כך שתדפיס את המספרים בסדר בהם נקלטו.


הפתרון
#include <stdio.h>
#include <stddef.h>
#include <malloc.h>
 
 
struct link_
{
  struct link_ *next;
 
  int data;
};
 
 
typedef struct link_ link;
 
 
struct list_
{
        link *head;
		link *tail;
        unsigned long size;
};
 
 
typedef struct list_ list;
 
 
/* Constructs a list (prepares it for use). */
void list_ctor(list *list);
 
/* Destructs a list (after use). */
void list_dtor(list *list);
 
/* Returns the number of elements in the list. */
unsigned long list_size(const list *list);
 
/* Pushes new data to the head of the list.
* Returns 0 if the operation succeeded, -1 otherwise. */
int list_push(list *list, int data);
 
/* Pops (removes) the element at the head of the list. 
* Returns the element.
* Don't call if the size of the list is 0. */
int list_pop(list *list);
 
/* Returns the element at the head of the list. 
* Don't call if the size of the list is 0. */
int list_head(const list *list);
 
 
void list_ctor(list *list)
{
  list->head = NULL;
  list->tail= NULL;
  list->size = 0;
}
 
 
void list_dtor(list *list)
{
  link *l = list->head;
 
  while(l != NULL)
  {
        link *const old = l;
 
        l = old->next;
 
        free(old);
  }
 
  list_ctor(list);
}
 
 
unsigned long list_size(const list *list)
{
  return list->size;
}
 
 
int list_push(list *list, int data)
{
  link *const l = (link *)malloc(sizeof(link));
 
  if(l == NULL)
    return -1;
 
  l->data = data;
  l->next = NULL;//putting it at end
  if(list->size==0)
  {
   list->head = l;
  }
  if(list->tail)//not null
  {
	  list->tail->next = l;//keeping the links
  }
    list->tail = l;
  ++list->size;
 
  return 0;
}
 
 
int list_pop(list *list)
{
  link *const l = list->head; 
  const int data = l->data;
 
  list->head = l->next;
  --list->size;
  if(!list->size)
  {
	  list->tail=list->head;
  }
  free(l);
 
  return data;
}
 
 
int list_head(const list *list)
{
  const link *const l = list->head; 
  return l->data;
}
 
 
int main()
{
  int c;
  list lst;
 
  list_ctor(&lst);
 
  do
  {
    int d;
 
    printf("Please enter a number: ");
    scanf("%d", &d);
 
    list_push(&lst, d);
 
    printf("Please enter 0 to quit, or any other number to continue: ");
    scanf("%d", &c);  
  }
  while(c != 0);
 
  printf("The numbers you entered, in reverse order, are:\n");
 
  while(list_size(&lst) > 0)
    printf("%d\n", list_pop(&lst));
 
  list_dtor(&lst);
  return 0;
}

 
}


שימוש חשוד ב-realloc

[עריכה]

מה חשוד בשורה הבאה:

p = realloc(p, sizeof(int) * 80);


הפתרון

נניח שהקריאה תיכשל. הפונקציה תחזיר במקרה זה NULL, והערך יושם בp. נשים לב שהזיכרון שאליו הצביע p לא שוחרר, מה שמעלה חשד שיש כאן דליפת זיכרון, כי אין אפשרות יותר לשחרר זכרון זה (אלא אם כן ערכו של p נשמר קודם במשתנה אחר).