4
votes

In the following code, the scanf() in main() turns one of the input numbers from a non-zero number into zero, as shown by a debugging printf() in the while loop. I've tested it on several compilers but only to keep getting the same result. Please help me out by telling me why this is such. Thank you.

 #include <stdio.h>

unsigned srl (unsigned x, int k)
{
    /* perform shift arithmetically */
    printf("x = %u, (int) x= %d\n", x, (int) x);
    unsigned xsra = (int) x >> k;
    printf("\nxsra before was: %u\n", xsra);
    unsigned test = 0xffffffff;
    test <<= ((sizeof (int) << 3) - k); // get e.g., 0xfff00...
    printf("test after shift is: %x, xsra & test = %x\n", test, xsra & test);
    if (xsra & test == 0) // if xsrl is positve
        return xsra;
    else
        xsra ^= test;    // turn 1s into 0s

    return xsra;
}

int sra (int x, int k) 
{
    /* perform shift logically */
    int xsrl = (unsigned) x >> k;
    unsigned test = 0xffffffff;
    test << ((sizeof (int) << 3) - k + 1); // get e.g., 0xffff00...
    if (xsrl & test == 0) // if xsrl is positve
        return xsrl;
    else 
                            xsrl |= test;

        return xsrl;
}

int main(void)
{
    int a;
    unsigned b;
    unsigned short n;

    puts("Enter an integer and a positive integer (q or negative second number to quit): ");
    while(scanf("%d%u", &a, &b) == 2 && b > 0)
    {
        printf("Enter the number of shifts (between 0 and %d): ", (sizeof (int) << 3) - 1);
        scanf("%d", &n);
        if (n < 0 || n >= ((sizeof (int)) << 3))
        {
            printf("The number of shifts should be between 0 and %d.\n", ((sizeof (int)) << 3) - 1);
            break;
        }
        printf("\nBefore shifting, int a = %d, unsigned b = %u\n", a, b);
        a = sra(a, n);
        b = srl(b, n);
        printf("\nAfter shifting, int a = %d, unsigned b = %u\n", a, b);
        puts("\nEnter an integer and a positive integer (q or negative second number to quit): ");
    }
    puts("Done!");

    return 0;
}
1
Specifier for unsgined short should be %hu and not %u.ameyCU
It would have been easier if you let me know which one was becoming 0 so I didn't have to compile the whole thing myself... (Well actually, I could figure it it was probably n after reloading and seeing amey's comment.) Also, OP, n can never be negative as it's unsigned.RastaJedi
He's actually using %d, not %u, for n, albeit still incorrect.RastaJedi
Thank you, ameyCU and RastaJedi. Your comments are very to-the-point and very helpful. This is a typical overflow, indeed.Michael May

1 Answers

4
votes

The problem is that n is an unsigned short, which has less size than a normal int. When you call scanf("%d", &n);, it reads the value into n and potentially overwrite the existing b value if b has the memory location right after n.

All you have to do is to change that problematic line into:

scanf("%hu", &n);

the h is a modifier for unsigned short int, from here.