NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Moc prosím o pomoc, nemůžu najít chybu

V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Šimon Fojtík:17.12.2017 18:16

main.c

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include "queue.h"


/* allocate new integer with value a and add it to the queue */
void add(int a, queue_t *queue)
{
   int *p = (int*)malloc(sizeof(int));
   *p = a;
   bool ret = push_to_queue(queue, (void*)p);
   if (!ret) {
      // free memory on failure
      free(p);
   }
}

/* print the int value on pointer p */
void print_int(void *p)
{
   if(p != NULL){
      printf("%d\n", *((int*)p));
   } else {
      printf("NULL\n");
   }
}

/* pop from the queue, print and free the element */
void pop(queue_t *queue)
{
   void *p = pop_from_queue(queue);
   print_int(p);
   free(p);
}

/* get i-th element and print it (do not remove them) */
void get(int idx, queue_t *queue)
{
   print_int(get_from_queue(queue, idx));
}

/*
 * TEST PROGRAM
 * - reads commands from stdin and executes them in the queue
 */
int main(int argc, char *argv[])
{
   int n;
   /* the tested queue */
   queue_t *queue;

   // read the size of the queue
   scanf("%d", &n);
   // create queue
   queue = create_queue(n);

   while (true) {
      char s[2];
      // read one command
      int ret = scanf("%1s", s);
      if (ret != 1) {
         break;
      }

      // add command
      if (s[0] == 'a') {
         int a;
         // read the argument of the command
         ret = scanf("%d", &a);
         if (ret != 1) {
            break;
         }
         add(a, queue);
         // remove command
      } else if (s[0] == 'r') {
         pop(queue);
         // get command
      } else if (s[0] == 'g') {
         int a;
         // read the argument of the command
         ret = scanf("%d", &a);
         if (ret != 1) {
            break;
         }
         get(a, queue);
      }
   }

   // remove rest of the elements in the queue
   while (get_queue_size(queue)) {
      void *p = pop_from_queue(queue);
      free(p);
   }

   // free memory
   delete_queue(queue);
   queue = NULL;

   // return 0 on succes
   return 0;
}

queue.h

#ifndef __QUEUE_H__
#define __QUEUE_H__

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

/* Queue structure which holds all necessary data */
typedef struct queue_t {
  int data;
  struct queue_t *dalsi;
} queue_t;

/* creates a new queue with a given size */
queue_t *create_queue(int capacity);

/* deletes the queue and all allocated memory */
void delete_queue(queue_t *queue);

/*
 * inserts a reference to the element into the queue
 * returns: true on success; false otherwise
 */
bool push_to_queue(queue_t *queue, void *data);

/*
 * gets the first element from the queue and removes it from the queue
 * returns: the first element on success; NULL otherwise
 */
void *pop_from_queue(queue_t *queue);

/*
 * gets idx-th element from the queue
 * returns the element that will be popped after idx calls of the
 * pop_from_queue()
 * returns: the idx-th element on success; NULL otherwise
 */
void *get_from_queue(queue_t *queue, int idx);

/* gets number of stored elements */
int get_queue_size(queue_t *queue);

#endif /* __QUEUE_H__ */

queue.c

#include "queue.h"

int pushcounter = 0;
int popcounter = 0;
int control = 0;
int velikost = 0;

queue_t *create_queue(int capacity) {
  velikost = capacity;
  queue_t *prvni = (queue_t *)malloc(capacity * sizeof(queue_t));
  return prvni;
}

bool push_to_queue(queue_t *queue, void *data) {
  if (control >= 0 && control <= velikost) {
    queue_t *a;
    a = queue + pushcounter;
    a->data = *((int *)data);
    if (pushcounter == velikost) {
      a->dalsi = queue;
      pushcounter = 0;
      control++;
    } else {
      a->dalsi = (queue + (1 + pushcounter));
      pushcounter++;
      control++;
    }
    return true;
  } else {
    return false;
  }
}

void *pop_from_queue(queue_t *queue) {
  if (control >= 0 && control <= velikost) {
    queue_t *a;
    a = queue + popcounter;
    popcounter++;
    if (popcounter == velikost) {
      popcounter = 0;
    }
    control--;
        return &(a->data);
  } else {
    return NULL;
  }
}

void *get_from_queue(queue_t *queue, int idx) {
  if (control >= 0 && control <= velikost && idx >= 0 && idx <= control) {
    queue_t *a;
    a = (queue + (popcounter + idx));
    int *b;
    b = &(a->data);
    return b;
  } else {
    return NULL;
  }
}

int get_queue_size(queue_t *queue) { return control; }

void delete_queue(queue_t *queue) {
  queue_t *a;
  for (int i = 0; i < velikost; i++) {
    a = (queue + i);
    free(&(a->data));
  }
}

Dobrý večer,
celý den píšu úkol z prográmka a už sem fakt zoufalý. Jde o to naprogramovat FIFO kruhovou frontu, kde mám zadaný program main.c, mám definovat strukturu v souboru queue.h a napsat celý souboru queue.c, pak vytvořit knihovnu.
Funkce push a get mi podle mě funguje bez problému, ten nastává ve funkci pop. První volání pop funkce proběhne bez chyby, při druhém volání však dostávám chybu Double free or corruption a nemůžu přijít na to proč.
Budu rád za jakoukoliv pomoc, sám na to už asi nepřijdu.

Editováno 17.12.2017 18:17
 
Odpovědět
17.12.2017 18:16
Avatar
Odpovídá na Šimon Fojtík
Matúš Olejník:17.12.2017 21:03

Môžeš dať ukážkový vstup prosím? :)

Nahoru Odpovědět
17.12.2017 21:03
/* I am not sure why this works but it fixes the problem */
Avatar
Odpovídá na Matúš Olejník
Šimon Fojtík:17.12.2017 21:42

Tohle jsou ukázkové vstupy a výstupy

1.in

3
a 1
a 2
a 3
r
r
r
r

1.out

1
2
3
NULL

2.in

3
a 1
g -1
g 0
g 1
r

2.out

NULL
1
NULL
1
 
Nahoru Odpovědět
17.12.2017 21:42
Avatar
expoox
Tvůrce
Avatar
expoox:18.12.2017 20:44

Ahoj, nemam pro tebe odpoved jen takovou malou buzeraci :) ten ukol znam a ty funkce mas mit implementovane v queue.h (ostatne proto tam jsou naznaceny) a druha vec je ze to nemuzes mit udelane jenom pro integer ale pro libovolny datovy typ

 
Nahoru Odpovědět
18.12.2017 20:44
Avatar
Odpovídá na expoox
Šimon Fojtík:19.12.2017 22:08

O tom ze to ma byt pro libovolny datovy typ vím, ale nejdriv sem si to chtel napsat tak aby to vubec fungovalo pro integer :D Jinak co by v tom pripade melo byt v queue.c? Z clanku primo tady na itnetwork jsem to pochopil tak, ze v .h si je jen deklaruji a v .c je pak definuji. dekuji za pripadnou odpoved

 
Nahoru Odpovědět
19.12.2017 22:08
Avatar
Odpovídá na Šimon Fojtík
Neaktivní uživatel:20.12.2017 0:12

Jestli jsem to po zbeznem prohlednuti pochopil dobre, tak v podstate to same, jenom data nebudou typu int ale void *. Takze nebudes muset zbytecne pretypovavat pri ukladani na int.

Jinak, co presne si slibujes od tohoto kusu kodu

a = queue + popcounter;

presne co ma za vyznam k pointeru pricitat integer?

Proc pri insertu do fronty nedelas malloc pro dalsi prvek spojaku?
Proc misto toho alokujes dynamicky hodnotu toho prvku, kdyz by stacilo normalne na stacku.
Trosku mi prijde, ze ten program nedela, to co mam pocit, ze by mel delat.

...

Hele jak na to koukam, ty si asi pletes pole a spojak. Protoze vidim, na vice mistech, ze se snazis indexovat pomoci pricitani integeru k pointeru ale to ti nemuze fungovat. Tak zkus napsat neco vic, k tomu a podivame se na to.

Nahoru Odpovědět
20.12.2017 0:12
Neaktivní uživatelský účet
Avatar
Šimon Fojtík:21.12.2017 12:11

Tak už jsem na to přišel, v podstatě to bylo celkem jednoduchý. Děkuji všem za rady

Akceptované řešení
+5 Zkušeností
Řešení problému
 
Nahoru Odpovědět
21.12.2017 12:11
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 7 zpráv z 7.