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
``````
``````// 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
``````
``````// 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
``````
``````// 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.

• Assume `malloc()` never returns `NULL`.
• `#include` directives have been omitted for brevity.
``````// 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.