COMS 3157 Advanced Programming

Recitation 3: Binary, Expressions, and Pointers

3.1 Bit operators

Without using any arithmetic or comparison operators (e.g., +, -, *, /, %, <, <=, >, >=, ==, or !=), fill in the blanks according to the description. Exception: you may use - only to account for off-by-one (e.g., x - 1 is ok; x - 32 or x - n is not).

Bonus: don’t assume that sizeof(int) == 4; make this work for any int size!

mul8(x) should return x * 8:

int mul8(int x) {
    return ________________; // (3.1.1)
}

make_odd(x) should return x if x is odd, and return x + 1 otherwise:

unsigned int make_odd(unsigned int x) {
    return ________________; // (3.1.2)
}

is_negative(x) should return 1 when x is negative, and 0 otherwise:

int is_negative(int x) {
    if (________________) // (3.1.3)
        return 1;
    else
        return 0;
}

set_bit(x, n, b) should return x, with its n-th bit is set to 1 if b is non-zero, and set to 0 otherwise (n is zero-indexed; set_bit(0, 0, 1) should return 1):

int set_bit(int x, int n, int b) {
    if (b)
        return ________________; // (3.1.4)
    else
        return ________________; // (3.1.5)
}

Solutions

Check out the solutions by checking out the examples on CLAC:

git clone ~j-hui/cs3157-pub/examples/bitmask

In this repo, the solutions are written in bitmask-solutions.h as macros; you can fill in bitmask.c yourself before looking at the solutions.

Build using make, test by running ./bitmask.

3.2 Evaluation order

Consider the following program:

#include <stdio.h>

int add(int x, int y) {
    return x + y;
}

int print_int(int x) {
    printf("%d\n", x);
    return x;
}

int main(void) {
    int x = 1, y = 2, z = 0;

    // CODE FRAGMENT HERE
}

What does the program print if we substitute the // CODE FRAGMENT HERE comment with each of the following code fragments? If the behavior of the program is not well-defined (e.g., undefined or unspecified behavior), write “UNSPECIFIED”.

// 3.2.1
if (print_int(z)) {
    print_int(y);
} else {
    print_int(x);
}
// 3.2.2
print_int(add(++x, ++x));
// 3.2.3
print_int(print_int(y) - print_int(x));
// 3.2.4
while (print_int(y) && print_int(z)) {
    print_int(x);
}
// 3.2.5
print_int(print_int(y) || print_int(x));
// 3.2.6
print_int(add(print_int(x), print_int(y)));
// 3.2.7
print_int(sizeof(print_int(x)) - sizeof(print_int(y)));
// 3.2.8
print_int(print_int(x) + x++);
// 3.2.9
print_int(add(y++, ++z));
// 3.2.10
while (print_int(y--) || print_int(--x)) {
    print_int(z);
}

Solutions

Check out the solutions by checking out the examples on CLAC:

git clone ~j-hui/cs3157-pub/examples/eval-order

In this repo, each part is in its own subdirectory, where the program is implemented in eval.c. See inline comments for answers and explanations; run make to build eval, which you can run to see the output for yourself (if the behavior is well-defined).

3.3 Memory leaks and errors

Each of the following programs try to print an integer, but only some succeed without memory leaks or errors. For each program, answer “ERROR” if there is a memory error, “LEAK” if there are no errors but it leaks memory, and “OK” if there are no memory errors or leaks.

// 3.3.1
int *m(int n) {
    return &n;
}

int main(void) {
    int *p = m(1);
    printf("%d\n", *p);
    return 0;
}
// 3.3.2
int g;
int *m(int n) {
    g = n;
    return &g;
}

int main(void) {
    int *p = m(1);
    printf("%d\n", *p);
    return 0;
}
// 3.3.3
int *m(int *n) {
    *n = 0;
    return n;
}

int main(void) {
    int i;
    int *p = m(&i);
    printf("%d\n", *p);
    free(p);
    return 0;
}
// 3.3.4
int *m(int n) {
    return malloc(n);
}

int main(void) {
    int *p = m(sizeof(int));
    printf("%d\n", *p);
    free(p);
    return 0;
}
// 3.3.5
int *m(int n) {
    int *p = malloc(n);
    *p = n;
    free(p);
    return p;
}

int main(void) {
    int *p = m(sizeof(int));
    printf("%p\n", p);
    return 0;
}
// 3.3.6
int *m(int n) {
    int *p = malloc(n);
    *p = n;
    return p;
}

int main(void) {
    int *p = m(sizeof(int));
    printf("%d\n", *p);
    free(p);
    free(p);
    return 0;
}
// 3.3.7
int *m(int *n) {
    if (n)
        *n = 1;
    return n;
}

int main(void) {
    int *p = m(malloc(sizeof(m(NULL))));
    printf("%d\n", *p);
    return 0;
}

Solutions

Check out the solutions by checking out the examples on CLAC:

git clone ~j-hui/cs3157-pub/examples/mem-safety

In this repo, each part is in its own subdirectory, where the program is implemented in mem.c. See inline comments for answers and explanations; run make to build mem, which you can run with valgrind to see whether there are memory leaks or errors.