Search code examples
cstructqueuepalindrome

C function, that receives a struct, and causes it to change outside of the function, even though the struct not sent as a pointer


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

typedef struct queue
{
    int *arr, // array to store values
    size, // queue size (array size)
    put, // index location which the next value will be pushed in
    take, // index location which the next value will be popped out
    countVals; // Counts the number of values that the queue contains
} queue;

// queue nitialization
void newQueue (queue *q, int size)
{
    if (size < 0)
        q->arr = NULL;
    else
    {
        q->arr = (int*) malloc (sizeof (int) * size);
        q->size = size;
        q->put = q->take = q->countVals = 0;
    }
}

// free array allocated to queue
void freeQueue (queue *q)
{
    free (q->arr);
}

// is the queue full?
int isFullQueue (queue q)
{
    return q.countVals == q.size;
}

// is the queue empty?
int isEmptyQueue (queue q)
{
    return q.countVals == 0;
}

// how many values queue contains?
int countQueueVals (queue q)
{
    return q.countVals;
}

// push value to queue
void pushQueue (queue *q, int val)
{
    if (q->arr && !isFullQueue (*q))
    {
        q->arr[q->put] = val;
        q->put = (q->put + 1) % q->size;
        q->countVals++;
    }
}

// pop out value from queue
void popQueue (queue *q)
{
    if (q->arr && !isEmptyQueue (*q))
    {
        q->take = (q->take + 1) % q->size;
        q->countVals--;
    }
}

// What is the value at top of queue
int topQueue (queue q)
{
    if (q.arr && !isEmptyQueue (q))
        return q.arr[q.take];
    return -1;
}

// show all queue values
void showQueue (queue q)
{
    if (q.arr)
        while (!isEmptyQueue(q))
        {
            printf ("%d ", topQueue(q));
            popQueue (&q);
        }
        //  printf ("\n");
}

// are values of queue arranged in palindrome?
int isQueuePalindrome (queue q)
{
    int i, num1, num2;
    queue tmpQ;

    if (!q.arr)
        return -1;

    newQueue (&tmpQ, q.countVals);
    while (!isEmptyQueue(q))
    {
        pushQueue (&tmpQ, topQueue(q));
        popQueue (&q);
    }

    while (tmpQ.countVals > 1)
    {
        for (i = 0; i < tmpQ.countVals - 1; i++)
        {
            num1 = topQueue (tmpQ);
            popQueue (&tmpQ);
            pushQueue (&tmpQ, num1);
        }

        num1 = topQueue (tmpQ);
        popQueue (&tmpQ);

        num2 = topQueue (tmpQ);
        popQueue (&tmpQ);

        if (num1 != num2)
        {
            freeQueue (&tmpQ);
            return 0;
        }
    }
    freeQueue (&tmpQ);
    return 1;
}

void main ()
{
    queue q;
    newQueue (&q, -1);
    showQueue (q);
    printf ("%d\n", isQueuePalindrome(q)); // -1
    newQueue (&q, 5);
    showQueue (q);
    printf ("-> %d\n", isQueuePalindrome (q)); // 1
    pushQueue (&q, 10);
    showQueue (q);
    printf ("-> %d\n", isQueuePalindrome (q)); // 1
    pushQueue (&q, 10);
    showQueue (q);
    printf ("-> %d\n", isQueuePalindrome (q)); // 1
    popQueue (&q);
    pushQueue (&q, 20);
    showQueue (q);
    printf ("-> %d\n", isQueuePalindrome (q)); // 0
    pushQueue (&q, 30);
    showQueue (q);
    printf ("-> %d\n", isQueuePalindrome (q)); // 0
    pushQueue (&q, 20);
    showQueue (q);
    printf ("-> %d\n", isQueuePalindrome (q)); // 0
    pushQueue (&q, 10);
    showQueue (q);
    printf ("-> %d\n", isQueuePalindrome (q)); // 1
}

I try to check with function, whether are values of queue arranged in palindrome.

I can't figure out why when I call the function, the function changes it values, even though I do't send the queue as a pointer. Also, I can't figure out why it's happens only when the queue is full.

The function checks the queue according to the following algorithm:

  1. If the queue has not been properly allocated it will be returned -1 (error).
  2. As long as the queue contains more then one value: i. Suppose that the queue actually contains n values, then it will pop out a value and push it back again and again n-1 times. ii. Now the next 2 values will be popped out. If they are equals, process will continue (without pushing them back). If they do not, it will end and be returned 0 (false).
  3. If the previous section will end, meaning that the queue is empty or contains only one value, so it will returned 1 (true, because it is a palindrome).

update:

Thanks to Christian Gibbons and Yunnosch, I fixed the problem with another queue (I could only copy the array, but I wanted the entire solution to be by queue).

I wonder if there is a way to check whether a queue is a palindrome without any additional data structure (queue, stack, array, etc.)?


Solution

  • If you copy a struct which contains a pointer, then the copy will contain the same pointer address, both point to the same memory.
    If you then change that memory, the pointers in both copies, though unchanged themselves, will point to the same memory, because they have not been changed, not in spite of that.
    So the copy and the original, both still contain the pointer pointing to the changed values.