$30
Problem A0 Scope, Life time and Initialization of global variables, local variables and static global/local variables
Download the files lab4A0.c and cal.c. Read the code first. Observe that for functions that have no parameters, they are declared as functionName(void), e.g., modify (void). It will also work if we declare them as functionNAme(), but the former is the preferred way of declaring such functions.
Compile (how?) and run the main program.
[Scope and initialization of global variables] Observe that global variables x and y, which are defined in cal.c, can be accessed in other file lab4A0.c (x and y have global scope), and in order to access x and y, the other file needs to declare them using keyword extern. Moreover, the output x:0 y:0 implies that global variables x and y, which were not initialized explicitly, all got initialized to 0 by the complier. Also observe how the function modify(), which was defined in cal.c, was declared and used in the other file. In declaring a function, keyword extern is optional.
Also observe how the values of x and y are changed in function modify() using compound operators, and how the second operation is evaluated following the operator precedence, giving y a new value 120, not 100 or 102.
[Scope of local variables] Next, uncomment the commented printf statemenqt (middle of the main function), and compile the files again. Observe the error message. The problem here is that local variable a’s scope is the block/function in which it is defined. Here a is defined in the if block, so it is not accessible outside the if block, even in the main function. Modify by declaring a before the if clause, i.e., change to int a; if (y != 0){ a = y;} Now a’s defining block is the main function, so a’s scope is anywhere in main after its declaration, which makes it accessible after the if block. Compile and run the program again.
[Lifetime of local variables] Uncomment the commented block near the end of main. Observe that function aFun is called several times, and all produce the same value for counter. This is because local variable counter in the function has life time ‘automatic’ – comes to life (allocated in memory) when function aFun is called and vanishes (deallocated from memory) when function aFun returns. So each time the function is call, a brand-new variable called counter is created and initialized. Thus it always has value 100.
[Initialization of local variables] Observe the initial values of local variable b in aFun. In C and Java, if a local variable is not explicitly initialized, it is not initialized to 0 (or, more precisely, it is initialized with some garbage value). Run the program again and you might see different values. [Lifetime of static local variables] Next, make counter a static local variable, compile and run again. Observe that the value of counter is different in each call and its value is maintained between the function calls, due to the fact that in C a static local variable has persistent lifetime over function calls, similar to global variable. (Note that, a static local variable’s scope is still within the block where it is defined. So counter is still not accessible outside the function. Try to access counter in main and you will get compiling error.) Also observe that compound operator += is used.
[Initialization of static local variables] Next, remove the initial value 100 for counter, compile and run again, and observe that in the first time call counter gets an initial value 0. As discussed in class, global variables and static local variables get initial value 0 if not initialized explicitly. (‘Regular’ non-static local variables such as b, as we observed above, are not initialized to 0, or, more precisely, are initialized with some garbage values).
[Scope of static global variables] Finally, make y in cal.c to be static and compile again. Observe that global variable y becomes inaccessible in main. (But it is still accessible later in file cal.c, where it is defined.)
.c
Problem A1 variable scope, “Pass-by-value”, tracing a program with debugger
Specification
In order to understand variable scope and pass-by-value in C, in this exercise we trace a program using a software tool called debugger, rather than using print statements. A debugger allows us to examine the values of variables during program execution. With a debugger, you can do this by setting several “breakpoints” in the program. The program will pause execution at the breakpoints and you can then view the current values of the variables.
You will use a GNU debugger call gdb. It is a command-line based debugger but also comes with a simple text-based gui (tui).
To debug a C program using gdb, you need to compile the program with –g flag of gcc.
Implementation
Note: for this exercise you may want to connect to lab environment, as you may not have the same debugger on your system.
Download the program swap.c, and compile using gcc –g swap.c. Then invoke gdb by issuing gdb –tui a.out. And then press enter key.
A window with two panels will appear. The upper panel displays the source code and the lower panel allows you to enter commands. Maximize the terminal and use arrow keys to scroll the upper panel so you can see the whole source code.
First, we want to examine the values of variables mainA and mainB after initialization. So we set a breakpoint at the beginning of line 11 (before line 11 is executed) by issuing break 11. Observe that a “b+” or ”B+” symbol appears on the left of line 11. We want to trace the values of variables x and y defined in function swap, both before and after swapping, so we set breakpoints at (the beginning of) line 18 and line 21. Finally we set a breakpoint at line 12 so that we can trace the value of mainA and mainB after the function call.
When the program pauses at a breakpoint, you can view the current values of variables with the print or display or even printf command.
Sample input/output red 64 % gcc –g swap.c red 65 % gdb –tui a.out
….
Reading symbols from a.out...done.
(gdb) break 11
Breakpoint 1 at 0x400488: file swap.c, line 11. (gdb) break 18
Breakpoint 2 at 0x4004a3: file swap.c, line 17. (gdb) break 21
Breakpoint 3 at 0x4004b5: file swap.c, line 21.
(gdb) break 12
(gdb) run
mainA = ? (gdb) display mainB mainB = ?
(gdb) continue
Continuing.
(gdb) display x x = ? (gdb) display y y = ?
(gdb) display mainA
……?
(gdb) display mainB
Breakpoint 3, swap (x=20000, y=1) at swap.c:21
(gdb) display x x = ? (gdb) display y y = ?
(gdb) continue
Continuing.
Breakpoint 4, main () at swap.c:12
(gdb) display mainA mainA = ? (gdb) display mainB mainB = ? (gdb) display x
……?
(gdb) display y What do you get for mainA and What do you get here, and
why? (gdb) quit
……? mainB? Are they swapped?
Submission Write your answers into a text file, and submit it. Or submit a snapshot of your gdb session. (Anything that show your work is acceptable.)
Problem A2 Variables
Specification
Complete the ANSI-C program runningAveLocal.c, which should read integers from the standard input, and computes the running (current) average of the input integers. The program terminates when -1 is entered.
Implementation
• Define a function void r_avg(int sum, int count)which, given the current sum sum and the total number of input count, computes and displays the running average in double. The current sum and input count are maintained in main.
• Complete main so that input is read and maintained. Don’t add printf statement in main.
Sample Inputs/Outputs:
red 307 % gcc –Wall runningAveLocal.c red 308 % a.out
Enter number (-1 to quit): 10
running average is 10 / 1 = 10.000 Floor is 10 Ceiling is 10
Enter number (-1 to quit): 20
running average is 30 / 2 = 15.000 Floor is 15 Ceiling is 15
Enter number (-1 to quit): 33
running average is 63 / 3 = 21.000 Floor is 21 Ceiling is 21
Enter number (-1 to quit): 47
running average is 110 / 4 = 27.500 Floor is 27 Ceiling is 28
Enter number (-1 to quit): 51
running average is 161 / 5 = 32.200 Floor is 32 Ceiling is 33
Enter number (-1 to quit): 63
running average is 224 / 6 = 37.333 Floor is 37 Ceiling is 38
Enter number (-1 to quit): -1 red 309 %
.out
Problem A3 Variables
Specification
Modify the above program, simplifying communications between functions.
Implementation
• download program runningAveLocal2.c.
• define a function void r_avg(int input),which, given the current input input, computes and displays the running average. Notice that unlike the function in A2, this function takes only one argument about current input and does not take current sum and input count as its arguments. In such an implementation, current sum and input count are not maintained in main. Instead, main just pass current input to r_avg(), assuming that r_avg() somehow maintains the current sum and input count info.
• do not modify or add to the code in main().
• do not use any global variable. How can function r_avg maintain the current sum and input count info?
Sample Inputs/Outputs:
Same as in problem A2.
Problem A4 Variables
Specification
Modify the program above, further simplifying communications between functions by using global variables.
Implementation
• download program runningAveGlobal.c. Complete the main()function. • download program function.c. Complete function void r_avg(), which computes and displays the running average. Notice that this function takes no arguments.
• define all global variables in function.c
Sample Inputs/Outputs:
Same as in problem A2.
Problem Pre-processing Macro
Download file lab4macro.c, compile and run it. Observe that,
• a parameterized macro MY_PRINT (x, y) is defined, to make the call simpler.
• a parameterized macro SQUARE(x) is defined, to calculate the square of parameter x;
• the SQUARE macro works correctly for argument i and j but not correctly for argument i+j. What went wrong? You may want to examine how the macro SQUARE is preprocessed. Issue gcc -E lab5macroSys.c, or, cpp lab5macroSys.c, which invokes gcc pre-processor only. Note that it is the code generated by the pre-processor (what you see here), not your original code, that is to be compiled. Look at the end of the screen, observe that:
o #include<stdio.h is replaced with the (lengthy) content of stdio.h, which is inserted before main(). Try to find the declarations (prototypes) of printf, scanf, getchar, putchar.
One way to filter an output in Unix/Linux is to use command grep, which we will cover later in the course. Issue command gcc -E lab5macroSys.c | grep printf
This will search for lines in the output of gcc -E that contain word ‘printf’. You will also see declarations of sprintf and fprintf that we mentioned in class.
Then issue gcc -E lab5macroSys.c | grep -w printf to do a ‘whole word
only’ search. This will search for lines that contain ‘printf’ as a whole word. Do the same search for scanf. o the commented code was removed o macro #define MY_PRINTF and marco #define SQUARE were processed
(removed). Their calls in main were textually replaced with actual parameters. Note how the call to SQUARE(i + j) was repalced.
Modify the macro to fix the problem. You should get 225 for SQUARE(i + j). After you made modifications to the macro, you might want to run gcc -E lab4macro.c again to see how the modified macro was processed by the preprocessor.
You can also comment out the first line #include<stdio.h, and run preprocessing again. Now the output is much shorter, because now no header file is inserted.
Next, uncomment the commented two lines, and run the program again. The output should be 0.0044. If you got other value, such as 1.0000, then see the pre-processed code to figure out why it does so. Then fix the macro to make it work correctly.
Finally, observe the pre-defined Macro __FILE__, __LINE__, __DATE__, __TIME__ , which contain the information about the current file, current date and time, are used. These information is useful for debugging programs.
lab30
In the rest of this lab you are going to practice using some C library functions. The simplified prototypes of the functions covered in this week’s lecture are listed below:
<stdio.h
printf() scanf()
getchar() putchar()
sscanf() sprintf()
fgets() fputs()
<string.h
int strlen(s) s strcpy(s,s) s strcat(s,s) int strcmp(s,s)
<ctype.h
int islower(int) int isupper(int) int isalpha(int) int isdigit(int) int isxdigit(int)
int tolower(int) int toupper(int)
<stdlib.h
int atoi(s) double atof(s) long atol(s) int rand(void) int abs(int) system(s) exit(int)
<math.h
sin() cos() double exp(x) double log(x) double pow(x,y) double sqrt(x) double ceil(x) double floor(x)
For exact prototypes of these functions, you can either 1) issue man 3 function_name in the terminal. 2) look at Appendix B of the required textbook.
You are encouraged to use these functions when appropriate, especially string functions declared in <string.h as well as string-related IO functions declared in <stdio.h. Don’t forget to include the corresponding header files. Moreover, if you use functions declared in <math.h, then on the lab environment you need to link the library by using –lm flag of gcc. That is, gcc x.c -lm
Problem B0 String manipulations, Library functions
Download file lab4B0.c. This short program first creates a character array and then uses string library function strcpy and strcat to change the content of the array. Observe that, • we need to include <string.h in order to use the string library functions.
• char array without initialization contains random values on some system (e.g., our lab). So don’t assume it is initialized with all \0 characters.
• strcpy(s1, s2) always copies whole source string s2 (from the beginning to the first \0 character -- inclusive) to the beginning of destination string s1.
o strncpy(s1, s2, n) copies first n character of course string s2 to the beginning of s1. If the first n character does not include the \0 of the s2, (i.e., n ≤ strlen(s2)), then no \0 is copied to the destination string s1.
• strcat(s1, s2) always appends whole s2 (from the beginning to the first \0 character - inclusive) to the end of s1. s1 may contain some characters so where is the end of s1? Starting from beginning of the array (the left end), the first \0 in s1 is considered the end of s1, thus the first character of s2 replaces the first \0 character in s1, gluing s1 and s2.
o strncat(s1, s2, n) appends the first n character of s2 to the end of s1. It always adds a \0 at the end of the n character (even if n ≤ strlen(s2)), terminating the destination string.
• strlen(s) and printf("%s",s) also treat the first \0 of s as the end of the string.
For more information about the library functions, type man followed by the function name in your terminal (man is a Unix command that stands for ‘manual’), e.g., man strcat
.
Problem B1 String manipulations, Library functions
Specification
Implement your version of strcat, called my_strcat.
Implementation
Download file lab4strcat.c. This program reads two words (strings with no spaces) from the user, stored them into arrays a and b. It then copies the inputs into another two arrays c and d, using library function strcpy. Then it calls strcat to concatenate a and b, and calls my_strcat to concatenate c and d. If implemented correctly, a and c should have the same content. The program terminates when user enters two xxx.
• Implement function void my_strcat(char []). Obviously, function should not call library function strcat. Also should not create extra temporary arrays in the function.
• Complete the while loop so that it keeps on prompting the user for inputs, and terminates when both two input strings are xxx, as shown in the sample output. Use strcmp library function to check the termination condition.
Sample input, output (assume each input has less than 30 characters and contains no space.) red 118 % a.out hello worlds strcat: helloworlds mystrcat: helloworlds
good ok strcat: goodok mystrcat: goodok hi g strcat: higmystrcat: hig
goodluck thanks
strcat: goodluckthanks mystrcat: goodluckthanks
xxx good strcat: xxxgood mystrcat: xxxgood
yy xxx strcat: yyxxx mystrcat: yyxxx
xxx xxx red 119 %
Problem B2 String manipulations, Library functions
Introduction
Consider the string library function strcmp(s,t). In Java there is a similar method string.compareTo(s). This function determines if s lexicographically precedes t (i.e., if s appears earlier than t in dictionary). It does so by comparing the two strings character by character. Issue man strcmp in the terminal , or search online resources to see how they work in C and Java
http://www.cplusplus.com/reference/cstring/strcmp/ https://www.geeksforgeeks.org/strcmp-in-c-cpp/ https://www.programiz.com/c-programming/library-function/string.h/strcmp https://overiq.com/c-programming-101/the-strcmp-function-in-c/
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareTo-java.lang.String-
Specification
Implement your version of strcmp, called my_strcmp, which does the same comparison.
Implementation
Download file lab4strcmp.c. This program reads two strings from the user, calls library function strcmp to compare their lexicographical ordering, and then calls function my_strcmp to compare the lexicographic ordering again. The program terminates when user enters two xxx.
• Implement function int my_strcmp(char []). Obviously, the function should not call library function strcmp. Note that your function doesn’t have to return exactly the same value as strcmp -- it needs to return a value that has the same sign as those returned by strcmp.
• Complete the while loop so that it keeps on prompting user for inputs, and terminates when both two input strings are xxx, as shown in the sample output. Use function strcmp or my_strcmp to check.
Sample input and output red 118 % a.out apple beast
strcmp: "apple" appears earlier in dictionary than "beast" mystrcmp: "apple" appears earlier in dictionary than "beast"
ace ave
strcmp: "ace" appears earlier in dictionary than "ave" mystrcmp: "ace" appears earlier in dictionary than "ave"
exit exam
strcmp: "exit" appears later in dictionary than "exam" mystrcmp: "exit" appears later in dictionary than "exam"
exam exam
"exam" and "exam" are same
"exam" and "exam" are same
exam examine
strcmp: "exam" appears earlier in dictionary than "examine" mystrcmp: "exam" appears earlier in dictionary than "examine"
examination exam
strcmp: "examination" appears later in dictionary than "exam" mystrcmp: "examination" appears later in dictionary than "exam" xxx hello
strcmp: "xxx" appears later in dictionary than "hello" mystrcmp: "xxx" appears later in dictionary than "hello"
xxx xxx
red 119 %
Problem C String manipulations, Library functions
Specification
Develop an ANSI-C program that reads user information from the standard inputs, and outputs the modified version of the records.
Implementation
Download file lab4fgets.c and start from there. Note that the program
• uses loop to read inputs (from standard in), one input per line, about the user information in the form of name age rate, where name is a word (with no space), age is an integer literal, and rate is a floating point literal. See sample input below.
• uses fgets() to read in a whole line at a time.
As discussed earlier, since the input contains space, using scanf("%s", inputArr) does not work here, as scanf stops at the first blank (or new line character if no space).
Consequently, if user enters Joe 2 2.3, only Joe is read in.
As mentioned in this week’s class, in order to read a whole line of input which may contain blanks, you can use scanf("%[^\n]s",inputsArr),or, depreciated function gets(inputsArr), but a much more common approach is to use function fgets().
Both these functions are declared in stdio.h. fgets(inputsArr, n, stdin) reads a maximum of n characters from stdin (Standard input) into array inputsArr.
The program should,
• after reading each line of inputs, if it is not "exit", output the original input using printf and fputs. Notice that since fgets reads in a '\n' at the end of input, printf does not need \n in the formatting string.
• then create a char array resu for the modified version of the input. In the modified version of input, the first letter of name is capitalized, age becomes age + 10, and rate has 100% increases with 3 digits after decimal point, followed by the floor and ceiling of the increase rate. The values are separated by dashes and brackets as shown below. the
• then output the resulting string resu.
• continue reading input, until a line of exit is entered. (How
Hints:
• When fgets reads in a line, it appends a new line character \n at the end (before \0). Be careful about this when checking if the input is exit.
• To create resu, you may want to tokenize the original input first, into several variables, then modify the variables, and then create resu from the modified variables. To tokenize a string and create a string from several variables, consider IO functions listed in page 6 of this pdf.
• If you use math library functions, be aware that the return type is double. Also if you run the program in our lab environment, need to compile the program using -lm flag of gcc.
Sample Inputs/Outputs:
red 118 % a.out
Enter name, age and rate: sue 22 33.3 sue 22 33.3 sue 22 33.3 Sue-32-66.600-[66,67]
Enter name, age and rate: john 60 1.0 john 60 1.0 john 60 1.0 John-70-2.000-[2,2]
Enter name, age and rate: lisa 30 1.34 lisa 30 1.34 lisa 30 1.34
Lisa-40-2.680-[2,3]
Enter name, age and rate: judy 40 3.2 judy 40 3.2 judy 40 3.2 Judy-50-6.400-[6,7]
Enter name, age and rate: exit red 119 %
Problem D0. 2D array, Library functions.
Download file lab4twoDarray.c. This short program demonstrates how to create, initialize 2D arrays, and access array elements. Read and run the program, and observe • the size of the 2D arrays.
• how to access 2D arrays at cell (element) level, using [][].
• that, for char 2D array, each row is essentially a 1-d char array (i.e., a string if it is \0 terminated). So each row can be feed into string library functions and printf directly, e.g., strlen(b[1]) strcpy(b[2], "Hello") printf("%s", b[i]). As a result, for example, we can print the char 2D array with one loop instead of two, whereas we need to use two loops for printing int 2D array.
Problem D1. 2D array, Library functions.
Specification
Write an ANSI-C program that reads user information from the standard inputs, and outputs both the original and the modified version of the records.
Implementation
A file lab4table1.c is for you to get started. The program should:
• use a table-like 2-D array (i.e., an array of ‘strings’) to record the inputs.
• use loop and scanf("%s %s %s") to read inputs (from standard in), one input per line, about the user information in the form of name age rate, where name is a word (with no space), age is an integer literal, and rate is a floating point literal. See sample input below.
• store each input string into the current available ‘row’ of the 2D array, starting from row 0.
• create a modified string of the input, and store it in the next row of the 2D array. In the modified version of input, all letters in name are capitalized, age becomes age + 10, and rate has 50% increases and is formatted with 2 digits after decimal point.
• continue reading input, until a name xxx is entered, followed by any age and rate values.
• after reading all the inputs, output the 2-D array row by row, displaying each original input followed by the modified version of the input.
• display the current date and time and program name before generating the output, using predefined pre-processor macros such as __FILE__, __TIME__ (implemented for you).
•
Note that as the partial implementation shows, each input line is read in as three ‘strings’ using scanf("%s %s %s", ….). In the next question, you will practice reading in the whole line as a string, as in lab4fgets (and then tokenize the string). Each approach has its pros and cons.
Note that you will lose all marks if, instead of a 2D-array, you use 3 parallel 1-D arrays -- one for all names, one for all ages, one for rates -- to store and display information.
Sample Inputs/Outputs:
red 307 % a.out
Enter name, age and rate: john 60 1.0
Enter name, age and rate: eric 30 1.3
Enter name, age and rate: lisa 22 2.2
Enter name, age and rate: Judy 40 3.2254
Enter name, age and rate: xxx 2 2
Records generated in lab4table1.c on Jun 10 2021 13:32:48 row[0]: john 60 1.0 row[1]: JOHN 70 1.50 row[2]: eric 30 1.3 row[3]: ERIC 40 1.95 row[4]: lisa 22 2.2 row[5]: LISA 32 3.30 row[6]: Judy 40 3.2254 row[7]: JUDY 50 4.84 red 308 %
Sample Inputs/Outputs: (download file inputD.txt) red 309 % a.out < inputD.txt
Enter name, age and rate: Enter name, age and rate: Enter name, age and rate: Enter name, age and rate: Enter name, age and rate: Enter name, age and rate:
Records generated in lab4table1.c on Jun 10 2021 13:42:03 row[0]: john 60 1.0 row[1]: JOHN 70 1.50 row[2]: Sue 30 1 row[3]: SUE 40 1.50 row[4]: Lisa 22 2.2 row[5]: LISA 32 3.30 row[6]: JuDy 40 3.22 row[7]: JUDY 50 4.83 row[8]: eric 30 1.3345 row[9]: ERIC 40 2.00 red 310
Problem D2. 2D array, library functions.
Specification
Same question as problem D1 but now you read each line of input as a whole line of string.
A file lab4table2.c is created for you to get started.
As the code shows, reading a whole line allows the input to be read into a table row directly. So you don’t have to store the original input into the table manually. The disadvantage, however, is that you may need to tokenize the line in order to get the name, age and rate information.
Sample Inputs/Outputs:
Same output as above, except that the generated file name is lab4table2.c now, and the time is different.
Problem E Pointer 101
Specification
Write your first (short) program that uses pointers.
Implementation
• define an integer age and initialize it to 10. Define another integer age2, which is initialized to 100;
ptr
age
• define an integer pointer variable ptr, and make it point to age • display the value of age, both via age (direct access), and via pointer ptr (indirect access).
• use ptr to change the value of age to 14;
• confirm by displaying the value of age, both via age and via its pointer ptr
ptr2
age2
• define another pointer variable ptr2, and make it point to age2
• assign triple of age’s value to age2 via pointer ptr and ptr2 (i.e., without referring to age and age2). age2 is 42 now.
• display the value of age2, both via age2, and via its pointer ptr2
ptr
age
ptr2
age2
• now let ptr2 point to age (too) by getting the address of age from pointer variable ptr (i.,e., without using &age)
• confirm by displaying the value of ptr2’s pointee via ptr2 • display value of age, both from age, and via ptr and ptr2.
• use ptr2 to decrease the value of age by 1. age is 13 now.
• display value of age, both from age, and via ptr and ptr2.
• finally, display the address of age, using printf("%p %p %p\n",&age,ptr,ptr2); Notice that here we print prt and ptr2 directly. This displays the content of the pointer variables, which is the address of age (in Hex).
Sample Inputs/Outputs:
red 305 % a.out age: 10 10 age: 14 14 age2: 42 42 ptr2’s current pointee: 14 age: 14 14 14
age: 13 13 13