CS 2301 Final Review
Give one advantage of using the preprocessor's #ifdef ... #endif directives to "comment out" unwanted source code, as compared to using the delimiters /* ... */ ?
#ifdef...#endif works with any block of source code -- using /* ... */ will not work if the block of source code includes comments delimited by /* ... */; that is because you cannot nest that type of comment. By using #ifdef, you can control which parts of the program get compiled by using options on the compiler command line; this can be done manually or in a makefile;
Suppose you want to pre-increment the variable i. How would you write that?
++i
Benefits of Symbolic Constants
1. Easier to modify (Only need to change in one place) 2. Easier to use (you can refer to it by name) 3. Ensures consistency between programs and between parts of a program, because they will all use the same value
What could happen, if the function tries to read pass the end of the array? (Give at least two possible outcomes.)
1. Get a segfault 2. You will read some random data that is stored in that part of the memory (if you are allowed to read it)
How many bytes (not bits) of memory does variable myfoo occupy on an x86_64 machine, and why?
16 bytes, 8 bytes for each of the doubles.
How many bytes (not bits) of memory does variable ptr_foo occupy on an x86_64 machine, and why?
8 bytes, because it is a pointer.
Unsigned Binary Integer
8-bit shown for clarity. Usually numbered from the right, starting at 0. Rightmost bit = low-order, a.k.a. Least Significant Bit (LSB). Leftmost bit = high-order, a.k.a. Most Significant Bit (MSB).
What is the type of the first argument of printf()
A String
In C, both globals and statics are declared outside of any function. What is the difference in where they are visible?
A global might be visible to any function in the program. A static is only visible to functions in the same .c source file where it was declared.
If your program uses a loop to step through the array b in order, why is it generally more efficient to ac-cess the elements of b by defining a pointer variable which initially points at the base of b, then gets in-cremented each time through the loop (using the ++ operator), rather than by using an index into the ar- ray, such as b[i]?
Adding a constant (such as 4, which is the size of an int) to a pointer is generally faster than multiplying and then adding, which is what the program has to do when using an index.
Sign-Magnitude
All except the MSB hold the value. Examples: • +5 = 00000101 • -5 = 10000101
What do we mean when we say that the C/C++ preprocessor only does textual substitution?
All the preprocessor does is work its way through the source code, obeying preprocessor directives, defines, and macros by substituting one block of text for another. It does not do any type checking or calculating
Suppose you declare an array in the main() function, and then pass it as a parameter to another function. A naïve programmer might say, "I do not have to pass the size of the array into the function; I can just use the sizeof operator inside the function." Explain why that will not work. What specific numeric value will the sizeof operator produce in this case on an x86_64 machine, and why?
The sizeof operator must be able to determine the size of the data at compile-time. There is no way for the compiler to know what size array will be passed into the function some time in the future. When you use sizeof on an array parameter inside a function, it produces the size of the pointer to the base of the array. Will produce 8 bytes b/c sizeof returns umber of bytes
The doxygen utility reads specially-formatted header comments to generate documentation. As far as the compiler is concerned, these are just comments, which it can skip over. Why does the compiler just treat these as comments?
These are regular comments which start with /* and end with */ . More specifically, everything between these two pairs of characters is treated as a comment.
Sometimes using the -- operator does not decrease the numeric value of a variable by 1; the value decreases by a different amount. In what case would this happen? How does the compiler decide how much to add? Give an example.
This can happen when the variable is a pointer. In that case, the numeric value decreases by the number of bytes in the type of variable being pointed at. For example, a pointer to int on x86 would be decremented by 4.
By default, on the systems we are using, where does the data go that gets sent by the program to standard error?
To the screen.
By default, on the systems we are using, where does the data go that gets sent by the program to standard output?
To the screen. That answer is sufficient. A more complete answer might be "to the terminal window."
Signed Binary Integers
Typically, use MSB as sign bit. • 0 = positive, 1 = negative. How to encode the value? • Sign-magnitude • Complement
Suppose the compiler sees a statement which calls (invokes) a function. Give two reasons why the compiler might need the information from a function prototype to correctly compile the statement.
How does the compiler use the information from the prototype? To check if the number and type of the parameters is correct. To properly handle the return value.
After running the doxygen utility, you have to copy the HTML files into your public_html directory, or into one of its subdirectories, in order for them to be visible to the Web server software. You must also set other+execute permission on your home directory, on public_html, and on any of its subdirectories. Why is that?
In order to access a file, the user running a program must have execute permission on the directory the file is in, and on all directories above it. The Web server software is running as its own user, not as you. Since you own the directories, the Web server is considered "other". So when it tries to reach your HTML files, the fact that other has execute permission means that it can access the files.
What is the difference between pre-decrementing and post-decrementing? Explain this in general.
In pre-decrementing, the value of the variable gets changed (decreased), and then the updated value is used. In post-decrementing, the value of the variable is used, and only after that does the value in the variable gets changed.
Legal Operations with Pointers
Increment a pointer, using ++. Decrement a pointer, using --. Subtract two pointers to get a length (Rarely used)
Twos Complement
Invert all the bits, then add 1. • +5 = 00000101 • -5 = 11111011 Consequences: • One less strictly positive than strictly negative numbers.
How many arguments does the function printf() takes
It can take several arguments depending on how many values you want to return
Ones Complement
Just invert all the bits. • +5 = 00000101 • -5 = 11111010 Consequences: • Both 0 and -0 exist. • Same quantity of strictly positive and strictly negative numbers.
MAKEFILES
LOOK AT QUIZ 2 #3 QUESTION
Tree -- Inorder
Left, Print, Right
Tree -- Postorder
Left, Right, Print
Is it acceptable to use pointers to local variables of a function, after that function has returned
No
Give two specific examples of something a program could do that would cause a segfault.
Uninitialized pointer Null pointer Off the end of an array or buffer Improperly-terminated character string.
Does this function produces a segfault or not, for incrementing the pointer x? Explain!! void addone(int *x){ int y = *(x++); printf("y = %d\n", y); }
No, because the address is used before incremented, so the actual address of x is used. The increment is done afterward and no used, therefore there is no segfault
What does the preprocessor do (if anything) in case of a type mismatch? Why?
Nothing. Since it only does textual substitution, the preprocessor does not check for type mismatches.
What do we mean when we say that a queue is FIFO (first-in-first-out)?
Once you have put things onto the queue, you can only remove them in the same order. That is, the first thing you put on the queue is the first one you can take off.
What do we mean when we say that a stack is LIFO (last-in-first-out)?
Once you have put things onto the stack, you can only remove them in reverse order. That is, the last thing you put on the stack is the first one you can take off.
In a #include directive, what is the difference between writing the name of the file between pointy brackets and between double quotation marks?
Pointy brackets tells the compiler to look for that file among the standard header files (by default, in Linux, in the directory /usr/include). Quotation marks tell the compiler to look somewhere else, typically among your own files (by default, in the current directory).
Tree -- Preorder
Print, Left, Right
When typing a command, how do you indicate that you want the program to run in the background? Why?
Use ampersand &. Want to do this so you can still type commands in the terminal without closing out of the text editor
The answers you gave to questions b) and c) should have been the same. So what is the difference between standard output and standard error, in terms of what they are supposed to be used for?
Standard output is used for the main output of the program. Standard error is used to output error messages.
What is the difference between when testing is done in a while loop, as compared to in a do ... while loop?
Testing is done at the start or beginning of a while loop while it is done at the end of a do...while loop. Therefore, the body of a do ... while loop is always executed at least once; a while loop might not get executed at all.
When passing an array into a function as a parameter, what value actually gets passed to the function?
The address of the zeroth element of the array.
Is it acceptable to use pointers to local variables of a function, while the function is active.
Yes
Is it acceptable to use pointers to structs allocated inside a function (using malloc()), after the function has returned.
Yes
Is it acceptable to use pointers to structs allocated inside a function (using malloc()), while the function is active.
Yes
Suppose your program uses a statement such as a = b[i]; where b is an array of ints. The compiler generates code which finds where b[i] is stored, then retrieves that value and stores it into the variable a. Describe briefly how this code determines the address of b[i].
The code takes the value of variable i, multiplies it by the size (number of bytes) in an integer, and adds it to the address of the base of array b (in other words, the address of b[0]). This gives the address of b[i].
What would be the correct type to fill in the blank? How many bytes in memory would the variable b occupy on an x86_64 machine? Is the actual value "R" stored in the variable b? If not, how many bytes does "R" occupy, and why? _____ b = "R";
The correct type would be char*. This occupies eight bytes in memory (because it is a pointer). The string "R" is stored somewhere else in memory; it occupies two bytes, because the system needs one byte for the letter and a second byte for the null terminator character.
What would be the correct type to fill in the blank? How many bytes in memory would the variable a occupy on an x86_64 machine, and why? Is the actual value 'R' stored in the variable a? If not, how many bytes does 'R' occupy, and why? _____ a = 'R';
The correct type would be char. This occupies one byte in memory, because that is how much space a single character needs. The ASCII value 'R' is stored in the variable a.
How does doxygen recognize the comments which it is supposed to use?
The doxygen comments start with /** . More specifically, since they start with /* the compiler does not care what the next character is. But doxygen knows to look for the second star
If a command-line argument is a number, such as 100, why do you generally need to pass it to a function such as atoi() or sscanf() before using that number?
The entry in argv[] is a character string. If we are going to use the quantity specified in the argument, we need to convert it into an integer or other kind of number.
When you pass an array into a function as a parameter, you generally have to also pass in the size of the array as a separate parameter. Why does this have to be a separate parameter?
The function only knows the size of the address of the array, not the actual array, so it needs to be in a separate parameter
In general, what does it mean when the system reports a segmentation fault (segfault)?
The hardware detects a segfault when a program tries to access a memory address which it is not authorized to access.
What is the name of the command you use to change the current directory?
cd
What is the name of the command you use to change mode (permissions)?
chmod
What will be the values of i and j after these lines have been executed? int i = 5; int j; i = i + 2;
i = 7 No way to predict what value j will have since it was not explicitly given a value -- j will have whatever number happens to be in those bytes.
Suppose you want to post-increment the variable i. How would you write that?
i++
What is the name of the command you use to list file names and attributes?
ls
What is the name of the command you use to find out how to use a particular command?
man
What command would you use to find which commands are concerned with a particular topic?
man with -k or use apropos command
Your program now has a variable myfoo which contains a struct of type foo. Write a C statement which would put the value 7.5 into data field x in that struct.
myfoo.x = 7.5;
What are the values of y and z, after the previous code is executed? int x =9; int y; int z; y = --x; z = y++;
x=8; y=9; z=8;
Set y equal to x, except that the rightmost five bits are forced to zero. Note: this has to work even if you do not know how many bits are in an integer.
y = x & (~ 0b11111);
Set y equal to x, shifted 3 bits to the right.
y = x >> 3;
Set every bit in y equal to the corresponding bit in x, except that the rightmost four bits of y are inverted compared to those bits in x.
y = x ^ 0b1111;
Set every bit in y equal to the corresponding bit in x, except that the rightmost two bits of y are all forced to one.
y = x | 0b11;
Set y equal to x, except that all the bits are inverted. Note: this has to work even if you do not know how many bits are in an integer.
y = ~x;
Illegal Operations with Pointers
• Adding two pointers. • Multiplying a pointer by anything. • Dividing a pointer by anything. • Dividing a pointer into anything.
By default, on the systems we are using, where does the data come from that gets sent into the program via standard input?
From the keyboard.
Why is a stack an appropriate place to put the local variables of a function when it is called?
Because if one function calls another function, the second function calls a third, and so on, each function must return in the reverse order of when it was called. This is LIFO, so it matches the way data is organized on a stack.
Why would a stack not be appropriate for holding data which you dynamically allocate using mal- loc() and calloc()?
Because memory blocks allocated that way could be freed by the program in any order, not necessarily in reverse order of being allocated.
When using printf(), why is it important to match each parameter with the corresponding conversion specifier in the format string?
Because printf() takes a variable number of parameters, it uses the format string to tell the number, type, and order of the parameters. Without that information, it cannot get the correct data off the stack.
The preprocessor cannot make decisions based on the value of C (or C++) variables. Why not?
Because the preprocessor operates at compile-time, the variables do not yet have values.
In C, the main() function takes two parameters (usually called argc and argv) to specify the contents of the command line. Why are two needed in C?
C has no objects, so the only way for main() to know how many elements are in the array is to have a separate parameter
%d = ? %f = ? %p = ? %c = ? %s = ?
Decimal integer. Double floating point. Pointer. Character. String.
Your program now also has a variable ptr_foo which contains a valid pointer to an existing struct of type foo. Write a C statement which would put the value 6.2 into data field y in that struct.
ptr_foo->y = 6.2;
What is the name of the command you use to tell the name of the current directory?
pwd
What would be the value of x and y, printed at the end? # include <stdio.h> void addone(int *x){ int y = *(x++); printf("y = %d\n", y); } int main(){ int x = 6; addone(&x); printf("x = %d",x); return 0; }
x = 6 and y = 6
What would be the values of x and y, after running the program? # include <stdio.h> void addone(int *x){ int y = (*x)++; printf("y = %d\n", y); } int main(){ int x = 6; addone(&x); printf("x = %d",x); return 0; }
x = 7 and y = 6
