Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

Practice Midterm Answers/Solutions

Question 1

B

0 is considered false in C, but any other number is considered true.

Question 2

Pass by reference vs pass by value. If a function is creating a person, then it doesn’t make

sense to pass the structure by value. Rather, you should either return a newly malloced

structure or pass an empty malloc-ed structure into createPerson (by reference) to update it with the initial values.

Think of this as a constructor, but the object construction is done through pass by reference.

Question 3

A and C will be the same. B is some stack location of the pointer. Remind yourself of how structures are organized in memory.

Question 4

I made this review before I knew this, but you actually don’t need to know realloc to the level of this question (as in, only the basics of realloc are being tested on the midterm). So, you can

ignore this question. But, the answer to this question is A.

If you passed in the reference, you would have to start at the same location as void *ptr.

Question 5

I’m in a rush, so for the first question, you can reference either any online source or the lecture slides for the ranges.

But, for the two advantages of two’s complement over one’s complement:

1.   Larger range than two’s complement than one’s complement

2.  Addition and subtraction happen as they would normally in binary (unlike one’s complement, where it’s a little trickier)

3.   The representation of 0 is unique (you can have 000000 . or 111111 .)

Question 6

The answer to this question is B. I thought this was an interesting question (definitely on the

harder side) as it demonstrates what integer overflow is. Integer’s limits are a little hard to work  with, so let’s say the problem was actually char b = 128; Remind yourself that character’s range is -128 to 127. Then, the value inside b is actually -128. Because after 127, it just loops back to -128. I don’t want to get into the specifics of exactly why this happens (it’s related to how 2s

complement and addition/subtraction happens) as you don’t need to know the math that well,     but it’s important to know that when a data type overflows, it “loops” to a number within the valid range of the number.

If you’re further inclined, you can email me or write a Piazza post, and one of the TAs or I can explain why further “looping” happens (or maybe I’ll update this document tonight).

Question 7

Operators in C only work on the primitive types, and so you can’t add two char* together. That’s why we have strcat instead.

Note additionally that there isn’t even a “string” data type in C, and so such concatenation wouldn’t work at all.

Question 8

The answer is C. In hindsight, this question is a little tricky and probably should have been written differently. I was trying to get at the idea that C doesn’t have booleans.

Even if you used , the true value is really just a macro for the integer 1. But, if you didn’t get this question, you can ignore it as long as you get that there isn’t a primitive type     boolean in C.

Question 8 (repeated question number oops)

A on the stack

*b → on the stack (the pointer itself)

The contents of *b → on the stack

*d → on the stack (the pointer itself)

The contents of *d → on the heap

c → neither stack or heap (you do NOT need to know where c is stored, just be able to identify that it is NOT on the stack/heap)

I think this should be straightforward aside from “the contents of *b” , and for this, remember that unless you malloc, memory is not on the heap. Since a is on the stack, the reference to an a is   just a stack address.

Question 9 through Question 12

The explanations for questions 9 through 12 are all the same. So I’ll have a long explanation and then have the answers for each of the questions (for the interest of time, if you have specific question, you can alway just post on piazza)

All four of these questions are of the same type. You are given some type of endianness (little or big). You are given the binary representation for a number, and we are casting the reference of some data type to another pointer data type. Here’s how I’d approach these problems systematically:

The key observation for this style of question is that because of the nature of pointers and how C works, pointers allow you to read any segment of memory. It doesn’t really matter what the    memory segment is, the type of the memory, etc.

1.   First, consider what type the initial pointer is. What is sizeof(the pointer type)?

2.   Then, consider what type the pointer is after the cast. What is sizeof(the new pointer type)?

3.   Remind yourself of the endianness that you are working with. Little or Big. (Don’tbe like me and forget what endianness is during recitation)

a.   Little Endianness — the typical endianness you will see across all your machines. iLab, your personal computer, etc

b.   Big Endianness — to be honest, never used a big endian machine, and I certainly do not want to!

4.   Based on the endianness, the answer to the question will definitely change. Why?

a.

b.   I took this picture off GeekForGeeks, but the idea is that the least significant bit is stored in the lower address while the most significant bit is stored in the larger

addresses.

i.      The reason I always get confused though is because Big Endianness

(atleast according to m e) is kinda how I always read numbers. When you read a number, you read left to right, where the leftmost of the number is  of more significance (numerically) than the rightmost of the number. (In     the number 123, the “ 1” has much higher significance than “3”). So don’t   be like me and do what you need to do to remember endianness.

ii.      Little Endian, to me atleast, seems like you’re reading the number right to left, which is weird to me (and I always get confused between the two).

c.   Your answer will most likely be “flipped” (or in reverse, etc) based on the endianness.

Once you have gathered all of this information, you can solve the question. Let’s see all this work on Question 12.

So let’s go through the four steps in order.

1.   It’s a char array, so it can be interpreted as a char pointer. We know that sizeof(char) is 1. I recommend knowing that sizeof(char) = 1, sizeof(short) = 2, sizeof(int) = 4,

sizeof(long) = 8, sizeof(float) = 4, sizeof(double) = 8.

2.   We cast to an int pointer. Sizeof(int) is 4 bytes. This means that we have X bytes. Then, with a cast to an integer pointer, we will make X / 4 reads of those bytes (since int

pointers read 4 bytes at a time).

a.   Remember you always read X / sizeof(the casted data type). Another example of this is when you have something like int *p = malloc(5 * sizeof(int)); and you do

*(p + 1). What you’re really doing is taking the starting address at p, and shifting it by 4 bytes. Since each integer is 4 bytes, you have really shifted to the next index in the array. If it was a char *p = malloc(5 * sizeof(char)); then *(p + 1) means

you’re shifting by only 1 byte (since a char is 1 byte).

i.      Think about pointers as holding memory addresses and you are shifting memory addresses. Since an integer is made up of 4 bytes, you would   need to shift 4 full addresses to get to the next consecutive integer.

3.   The question (and all of them for that matter) says that we’re working in a little-endian system.

Now, we put all this together. First, let’s represent char a[] in binary form (because remember, in a computer, everything is just binary, it’s just a bunch of 0s and 1s at the end of the day. It isn’t   stored as strings, integers, or anything. Just 0s and 1s)

char a[] = 00000000 01000001 01000010 01000011

So this is what it looks like in memory. We’re not being super formal in terms of notation — just   trying to drive the point. Now, the cast tells us that we’re going to be reading all 4 of these bytes. The question does NOT ask you to convert this binary representation to base 10. You will never be asked to do something like that on an exam. Even with a calculator, this is difficult to do.

Since the system is little endian, all you have to do now is just flip this and you get your answer. That is, the answer to the binary representation of c is

01000011 01000010 01000001 00000000 = 1128415488

I put the number there just in case someone wants to compile this and dissect it further. You don’t have to go to wolfram alpha or something and convert the binary number to base 10.

You can do the same steps for each of these questions and solve them. They aren't so bad once you see them 2-3 times.

Question 13

Discussed several times during lecture/recitation, but dynamic memory is needed when you

need variables to live outside allocation scope or when amount of memory is unknown. You

can’t guess the amount of memory your program could use because you might just be wrong as it’s hard to do and it’s wasteful programming.

The heap is also a large expanse of memory so it’s best to use that and store your data structures efficiently there.

Question 14

It’s actually exactly what the hint says (basically gave the answer with the hint oops). If you

didn’t have a null terminating character, the string library functions such as strlen, strcat, strdup, etc, won’t even work because the library won’t know where the string ends.

In general, it’s the same for memory representation. Try working with a string that you set (not a string literal, I mean an actual array of characters) without the null terminating character, and

you’ll see what I mean. It just doesn’t work unless you’re lucky or you are working with small string sizes (less than 5).

Question 15

Again, you don’t need to know realloc at this level. The answer is C though. B and D don’t make sense. For A, if you freed the initial pointer, then you can’t set the new memory to previous

contents (you would get a heap-use-after-free error because you can’t use something after you free it).

Question 16

The addresses are the same. The key insight is that pointers hold addresses — this question   tests how well you understand that idea. One of the biggest themes across this entire midterm will absolutely be the idea that pointers don’t point, they just hold a memory address. They

“point” to the contents they hold, but the variable itself just holds a memory address.

Here, when you do struct Way *g = f, you basically set the pointer of g to be the address that is HELD WITHIN f (NOT address OF). This means till you do something with g, the value within g is always going to just be that same address.

I was going to give this as a bonus, but it seems like I forgot to write it. But, if you do anything with that with the address within g, the behavior is undefined. Think about why this is true.

Question 17

I actually meant to put this question at the top, but then I would have to reorder each question.

The answer is just 0, 1, 2… , 9. It’s a function that demonstrates pass by value (since the array is being passed by value, you're not reallocating the array or anything, and so you are passing the  array by value).

Also, fun fact: iota is actually a C++ function that does what the iota function here does.

Basically, it starts at some number, and fills the array values with consecutive numbers after.

Question 18

You cannot update a pointer’s location and call free from a different location (different from the   starting location of the malloc). Oftentimes, this is called a misaligned pointer — you didn’t need to know that term, but you do need to know that you cannot free yourself from a different

location than where the malloc starts at.

You do not need to know the specific reason for this besides the fact that it’s a standard protocol by malloc. If you’re inclined, you can either google the reason why (it’s something to do with how malloc is implemented) or you will learn about this in later system courses.

Question 19

Ignore this question. Seems like this is the second time I failed at making a question of this type. I’ll have to look at this more.

Question 20

You just flip all the bits and add 1. No tricks 9

Question 21

This was question 3 on the paper quiz (it’s randomized question numbers for the canvas quiz takers).

Here’s a simplified solution.

In pointerArray(), since you have malloc-ed the array, when you access &a, that’s the pointer to the pointer, so it’s the reference of a heap address, which is just some address on the stack.

In normalArray(), this is not the case, since everything is on the stack. The key is to consider the reference type. The reference type for int a[5] is int (*)[5], which has sizeof as 20. Thus, when

you do &a + 1 → you get to the end of the array, and hence the iteration works.

I’ll update this soon for a better explanation, just wanted to finish the solution guide for now with something.