ECS 36A编程设计辅导、讲解c/c++语言程序、辅导program编程 讲解R语言编程|讲解Processing
- 首页 >> Matlab编程 ECS 36A: Programming Assignment #8
Contents
1 Changelog 1
2 General Submission Details 1
3 Grading Breakdown 1
4 Submitting on Gradescope 2
4.1 Regarding Autograder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
4.1.1 Visible Test Cases’ Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
5 Your Programming Tasks 3
5.1 Part #1: getProduct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
5.2 Part #2: linearSearch() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5.3 Part #3: Copy to Multiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5.4 Part #4: Run Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1 Changelog
You should always refer to the latest version of this document.
• v.1: Initial version.
• v.2: Fixed typo in the very last assertion in testLinearSearch().
• v.3: Autograder details.
2 General Submission Details
Partnering on this assignment is prohibited. If you have not already, you should read the section on
academic misconduct in the syllabus.
This assignment is due the night of Monday, December 14. Gradescope will say 12:30 AM on Tuesday, December 15, due
to the “grace period” (as described in the syllabus). Be careful about relying on the grace period for extra time; this could be
risky.
You should use the -Wall and -Werror flags when compiling. The autograder will use these flags when it compiles your
program.
3 Grading Breakdown
The autograder score will be out of 50 points. Each of the four parts is worth around 12.5 points.
∗This content is protected and may not be shared, uploaded, or distributed.
1
4 Submitting on Gradescope
You should only submit prog8.c and the two shell scripts. You may be penalized for submitting additional files. You have
infinite submissions until the deadline.
During the 10/02 lecture, I talked about how to change the active submission, just in case that is something that you
find yourself wanting to do.
4.1 Regarding Autograder
Your output must match mine exactly.
There is a description about how to interpret some of the autograder error messages in the directions for the previous
two programming assignments. I will not repeat that description here.
4.1.1 Visible Test Cases’ Inputs
Parts #1 and #2: See test_getProduct.c and test_linearSearch.c on Canvas. (These are different from the testGetProduct.c
and testLinearSearch.c files used in the examples below.)
Part #3:
Case #1:
1 ./ cp_mult . sh hi
2 echo $?
Case #2:
1 mkdir d1 d2 d3 d4
2 echo -e "123\ n45 \ n78 " > vals2 . txt
3 ./ cp_mult . sh vals2 . txt d4 d1 d3 d2
4 echo -e "=== retval ==="
5 echo $?
6 echo -e "=== d4 / vals2 . txt ==="
7 cat d4 / vals2 . txt
8 echo -e "=== d1 / vals2 . txt ==="
9 cat d1 / vals2 . txt
10 echo -e "=== d3 / vals2 . txt ==="
11 cat d3 / vals2 . txt
12 echo -e "=== d2 / vals2 . txt ==="
13 cat d2 / vals2 . txt
Case #3:
1 mkdir foo goo bar
2 echo -e " blah \ nblah \ nblah \ nblah " > foo / vals3 . txt
3 ./ cp_mult . sh foo / vals3 . txt goo / vals3 . txt bar / vals3 . txt
4 echo -e "=== foo / vals3 . txt ==="
5 cat foo / vals3 . txt
6 echo -e "=== goo / vals3 . txt ==="
7 cat goo / vals3 . txt
8 echo -e "=== bar / vals3 . txt ==="
9 cat bar / vals3 . txt
Part #4:
Case #1:
1 echo " old contents to overwrite " > blah . txt
2 ./ run_steps . sh echo 18 27 3 blah . txt
3 cat blah . txt
Case #2:
1 chmod +x do_math . sh
2 ./ run_steps . sh ./ do_math . sh -30 50 10 math_output . txt
3 cat math_output . txt
do_math.sh: (available on Canvas)
1 #!/ bin / bash
2
3 echo " Add 2: "$ (( $1 + 2) )
4 echo " Subtract 1: "$ (( $1 - 1) )
Case #3:
2
1 gcc - Wall - Werror foo .c -o foo
2 ./ run_steps . sh ./ foo 35 115 15 the_output . txt
3 cat the_output . txt
foo.c: (available on Canvas)
1 # include < stdio .h >
2 # include < stdlib .h >
3
4 int main ( int argc , char * argv [])
5 {
6 int num = atoi ( argv [1]) ;
7 if ( num < 50)
8 printf (" Less than 50.\ n ") ;
9 else if (50 <= num && num <= 100)
10 printf (" Between 50 and 100 ( inclusive ) .\ n ") ;
11 else
12 printf (" Greater than 100.\ n ") ;
13 }
5 Your Programming Tasks
In this assignment, you will implement two C functions and two shell scripts. The two C functions go in a file named
prog8.c, and each of the names of the shell scripts is given in the respective part.
Your program should have no memory leaks.
Below is a list of headers that you are allowed to include in prog8.c. You may not need all of these.
• prog8.h
•
•
•
•
•
•
•
5.1 Part #1: getProduct()
In prog8.c, implement a recursive function called getProduct() that takes as arguments an array of integers and the length
of this array. This function should return the product of this array’s values.
No input validation is necessary. (I want you to focus on learning recursion.) Thus:
• arr, as initially provided, will never be NULL. (Depending on your base case(s), it may become NULL.)
• arrLen, as initially provided, is always correct. (When performing a recursive call, be careful to not make arrLen become
incorrect.)
You are not allowed to use a loop for this part, since you must use recursion in a meaningful way. Your
approach should check and potentially act on the first element and then recurse on the rest of the array (i.e. the second
element onwards).
Here is what an implementation of getProduct() would look like if pointer arithmetic were not used. The index would have
to be an argument. You are not allowed to do this, since you are forced to use pointer arithmetic due to the fact that the
two parameters are set (in prog8.h) and you cannot change them. However, this should give you a good starting point.
1 int getProduct ( int * arr , int arrLen , int index )
2 {
3 if ( index == arrLen - 1)
4 return arr [ index ];
5 else
6 return arr [ index ] * getProduct ( arr , arrLen , index + 1) ;
7 }
Cautionary Tip: Be careful about using the prefix/postfix operators. If used improperly, you can encounter a compiler
error message that says something about sequencing. Here is an example to illustrate the concept. The error occurs because
in the line int b = a + ++a;, it is unclear if the left hand side of the addition (i.e. a) should be the old value of a (i.e. 3)
or the new value of a (i.e. 4). With the appropriate compiler flags, this triggers a compiler error. Without these flags, gcc
3
simply makes an assumption about which value of a to use, which is bad, because this is undefined behavior and potentially
inconsistent across different platforms.
1 $ cat main .c
2 # include < stdio .h >
3
4 int main ()
5 {
6 int a = 3;
7 int b = a + ++ a;
8 printf ("% d\n ", b);
9 }
10 $ gcc - Wall - Werror main . c
11 main .c: In function ’main ’:
12 main .c :6:17: error : operation on ’a ’ may be undefined [- Werror = sequence - point ]
13 int b = a + ++ a;
14 ^~~
15 cc1 : all warnings being treated as errors
16 $ gcc main .c
17 $ ./ a. out
18 8
19 $
Below are the test cases that I provide to you on Canvas. assert() takes as argument a boolean (usually a boolean
experssion) and crashes if the expression is false, reporting a diagnostic message if that occurs.
1 $ cat testGetProduct .c
2 # include " prog8 .h"
3
4 # include < assert .h >
5 # include < stdio .h >
6
7 void testGetProduct ( void )
8 {
9 {
10 int arr [] = {5 , 8, 3, -1};
11 assert ( getProduct ( arr , 4) == -120) ;
12 }
13 {
14 int arr [] = { -7 , 14 , -2};
15 assert ( getProduct ( arr , 3) == 196) ;
16 }
17 {
18 int arr [] = {5 , 15 , 0, 100 , -3};
19 assert ( getProduct ( arr , 5) == 0) ;
20 }
21 {
22 int arr [] = {2};
23 assert ( getProduct ( arr , 1) == 2) ;
24 }
25 {
26 int arr [] = {27 , 15 , 3 , 14 , 0 , -5, 2, 0};
27 assert ( getProduct ( arr , 8) == 0) ;
28 // Can " lie " about the array size .
29 assert ( getProduct ( arr , 4) == 27 * 15 * 3 * 14) ;
30 assert ( getProduct ( arr , 2) == 27 * 15) ;
31 assert ( getProduct ( arr , 1) == 27) ;
32 // Demonstrating some pointer arithmetic .
33 assert ( getProduct ( arr + 1, 1) == 15) ;
34 assert ( getProduct ( arr + 1, 2) == 45) ;
35 assert ( getProduct ( arr + 1, 3) == 45 * 14) ;
36 assert ( getProduct ( arr + 5, 2) == -10) ;
37 }
38 fprintf ( stderr , "%s(): All test cases passed !\n", __FUNCTION__ ) ;
39 }
40
41 int main ()
42 {
43 testGetProduct () ;
44 }
45 $ gcc - Wall - Werror -g testGetProduct . c prog8 .c -o testGetProduct
46 $ ./ testGetProduct
47 testGetProduct () : All test cases passed !
48 $
4
5.2 Part #2: linearSearch()
In prog8.c, implement a recursive function called linearSearch() that takes as arguments an array of integers, the length
of this array, and a target integer. This function should return true (i.e. a non-zero integer) if the array contains the target
and false (i.e. zero) otherwise.
No input validation is necessary. (I want you to focus on learning recursion.) Thus:
• arr, as initially provided, will never be NULL.
• arrLen, as initially provided, is always correct.
You are not allowed to use a loop for this part, since you must use recursion in a meaningful way.
Below are the test cases that I provide to you on Canvas.
1 $ cat testLinearSearch . c
2 # include " prog8 .h"
3
4 # include < assert .h >
5 # include < stdio .h >
6
7 void testLinearSearch ( void )
8 {
9 {
10 int arr [] = {5 , 8, 3, -1};
11 assert ( linearSearch ( arr , 4, 8) );
12 assert (! linearSearch ( arr , 4, -7) );
13 assert ( linearSearch ( arr , 4, -1) ) ;
14 assert (! linearSearch ( arr , 4, 50) );
15 }
16 {
17 int arr [] = { -5 , -2 , 2 , -2, 3 , 4 , 1};
18 assert ( linearSearch ( arr , 7, -2) ) ;
19 assert ( linearSearch ( arr , 7, -5) ) ;
20 assert (! linearSearch ( arr , 7, 14) );
21 assert (! linearSearch ( arr , 7, 20) );
22 // Again , we can " lie " about the length .
23 assert (! linearSearch ( arr + 1 , 6 , -5) );
24 assert ( linearSearch ( arr + 1, 6, -2) );
25 assert ( linearSearch ( arr + 1, 6, 2) );
26 assert (! linearSearch ( arr + 3 , 4 , 2) );
27 }
28 fprintf ( stderr , "%s(): All test cases passed !\n", __FUNCTION__ ) ;
29 }
30
31 int main ()
32 {
33 testLinearSearch () ;
34 }
35 $ gcc - Wall - Werror -g testLinearSearch .c prog8 .c -o testLinearSearch
36 $ ./ testLinearSearch
37 testLinearSearch () : All test cases passed !
38 $
5.3 Part #3: Copy to Multiple
Filename: cp_mult.sh
Motivation: Recall that the cp command can be used to copy multiple files into a destination directory, but it cannot be
used to copy one file into multiple destinations. You will write a script that does that.
Write a shell script that takes as argument a regular file (i.e. never a directory) and a list of destinations. The script
should copy the file into each of the given destinations. If not enough arguments are provided, then a usage message should
be printed and the script should return 1 (with exit 1); otherwise, the script should return 0. Note that just like cp, cp_mult.sh
can be used to make multiple copies of a file in the same directory.
Below are some examples of how your script should behave.
1 $ ls d1
2 $ ls d2
3 $ cat vals . txt
4 5
5 18
6 3
7 7
5
8 $ ./ cp_mult . sh vals . txt d1 d2
9 $ echo $?
10 0
11 $ cat vals . txt
12 5
13 18
14 3
15 7
16 $ ls d1
17 vals . txt
18 $ ls d2
19 vals . txt
20 $ ./ cp_mult . sh
21 Usage : ./ cp_mult . sh [ src ] [ dest1 ] ...
22 $ echo $?
23 1
24 $ ./ cp_mult . sh vals . txt
25 Usage : ./ cp_mult . sh [ src ] [ dest1 ] ...
26 $ ls *. txt
27 vals . txt
28 $ ./ cp_mult . sh vals . txt vals2 . txt vals3 . txt vals4 . txt
29 $ cat vals2 . txt
30 5
31 18
32 3
33 7
34 $ cat vals3 . txt
35 5
36 18
37 3
38 7
39 $ cat vals4 . txt
40 5
41 18
42 3
43 7
44 $
5.4 Part #4: Run Steps
Filename: run_steps.sh
Motivation: As a happy undergraduate student, I encountered several situations in which I had to run an executable
multiple times with different command-line arguments and collect the output of each of those runs. As you can hopefully
imagine, doing this manually (i.e. typing each line into the terminal) would have been annoying; you can save time on such
a task by writing a script like the one you will write for this part.
Write a script that takes five arguments:
• A command to run (which could be an executable compiled with gcc). Note that it must be the exact command needed
to run it, not just the executable’s name (which is why you see ./test in the example instead of test).
• A start integer A.
• An end integer B.
• A step integer S.
• An output file.
The script should perform a series of runs of the given command. The first run should have A be passed as argument to
the command to run. In the next run, A + S should be passed. After that, A + 2S, then A + 3S, then A + 4S, and so on,
until the value passed would exceed B. Each run’s results should be logged into the output file. You may not assume this
output file exists, and its old contents should be overwritten.
The script assumes that the executable only takes an integer as its only command-line argument. If not enough arguments
are provided, then a usage message should be printed and the script should return 1 (with exit 1); otherwise, the script should
return 0.
Below are some examples of how your script should behave.
1 $ cat test .c
2 # include < stdio .h >
3
4 int main ( int argc , char * argv [])
5 {
6
6 printf (" Provided : %s \n", argv [1]) ;
7 }
8 $ gcc - Wall - Werror test . c -o test
9 $ ./ run_steps . sh ./ test 10 100 5 output1 . txt
10 $ cat output1 . txt
11 === 10 ===
12 Provided : 10
13 === 15 ===
14 Provided : 15
15 === 20 ===
16 Provided : 20
17 === 25 ===
18 Provided : 25
19 === 30 ===
20 Provided : 30
21 === 35 ===
22 Provided : 35
23 === 40 ===
24 Provided : 40
25 === 45 ===
26 Provided : 45
27 === 50 ===
28 Provided : 50
29 === 55 ===
30 Provided : 55
31 === 60 ===
32 Provided : 60
33 === 65 ===
34 Provided : 65
35 === 70 ===
36 Provided : 70
37 === 75 ===
38 Provided : 75
39 === 80 ===
40 Provided : 80
41 === 85 ===
42 Provided : 85
43 === 90 ===
44 Provided : 90
45 === 95 ===
46 Provided : 95
47 === 100 ===
48 Provided : 100
49 $ ./ run_steps . sh ./ test 50 80 10 output2 . txt
50 $ cat output2 . txt
51 === 50 ===
52 Provided : 50
53 === 60 ===
54 Provided : 60
55 === 70 ===
56 Provided : 70
57 === 80 ===
58 Provided : 80
59 $ cat test2 .c
60 # include < stdio .h >
61 # include < stdlib .h >
62
63 int main ( int argc , char * argv [])
64 {
65 int num = atoi ( argv [1]) ;
66 if ( num < 100)
67 printf (" Less than 100.\ n ") ;
68 else
69 printf (" Greater than or equal to 100.\ n ") ;
70 }
71 $ gcc - Wall - Werror test2 .c -o test2
72 $ ./ run_steps . sh ./ test2 97 104 2 output3 . txt
73 $ echo $?
74 0
75 $ cat output3 . txt
76 === 97 ===
77 Less than 100.
78 === 99 ===
79 Less than 100.
7
80 === 101 ===
81 Greater than or equal to 100.
82 === 103 ===
83 Greater than or equal to 100.
84 $ ./ run_steps . sh ./ test2 97 104
85 Usage : ./ run_steps . sh [ executable ] [ start ] [ end ] [ step ] [ outfile ]
86 $ echo $?
87 1
88 $
8
Contents
1 Changelog 1
2 General Submission Details 1
3 Grading Breakdown 1
4 Submitting on Gradescope 2
4.1 Regarding Autograder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
4.1.1 Visible Test Cases’ Inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
5 Your Programming Tasks 3
5.1 Part #1: getProduct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
5.2 Part #2: linearSearch() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5.3 Part #3: Copy to Multiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5.4 Part #4: Run Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1 Changelog
You should always refer to the latest version of this document.
• v.1: Initial version.
• v.2: Fixed typo in the very last assertion in testLinearSearch().
• v.3: Autograder details.
2 General Submission Details
Partnering on this assignment is prohibited. If you have not already, you should read the section on
academic misconduct in the syllabus.
This assignment is due the night of Monday, December 14. Gradescope will say 12:30 AM on Tuesday, December 15, due
to the “grace period” (as described in the syllabus). Be careful about relying on the grace period for extra time; this could be
risky.
You should use the -Wall and -Werror flags when compiling. The autograder will use these flags when it compiles your
program.
3 Grading Breakdown
The autograder score will be out of 50 points. Each of the four parts is worth around 12.5 points.
∗This content is protected and may not be shared, uploaded, or distributed.
1
4 Submitting on Gradescope
You should only submit prog8.c and the two shell scripts. You may be penalized for submitting additional files. You have
infinite submissions until the deadline.
During the 10/02 lecture, I talked about how to change the active submission, just in case that is something that you
find yourself wanting to do.
4.1 Regarding Autograder
Your output must match mine exactly.
There is a description about how to interpret some of the autograder error messages in the directions for the previous
two programming assignments. I will not repeat that description here.
4.1.1 Visible Test Cases’ Inputs
Parts #1 and #2: See test_getProduct.c and test_linearSearch.c on Canvas. (These are different from the testGetProduct.c
and testLinearSearch.c files used in the examples below.)
Part #3:
Case #1:
1 ./ cp_mult . sh hi
2 echo $?
Case #2:
1 mkdir d1 d2 d3 d4
2 echo -e "123\ n45 \ n78 " > vals2 . txt
3 ./ cp_mult . sh vals2 . txt d4 d1 d3 d2
4 echo -e "=== retval ==="
5 echo $?
6 echo -e "=== d4 / vals2 . txt ==="
7 cat d4 / vals2 . txt
8 echo -e "=== d1 / vals2 . txt ==="
9 cat d1 / vals2 . txt
10 echo -e "=== d3 / vals2 . txt ==="
11 cat d3 / vals2 . txt
12 echo -e "=== d2 / vals2 . txt ==="
13 cat d2 / vals2 . txt
Case #3:
1 mkdir foo goo bar
2 echo -e " blah \ nblah \ nblah \ nblah " > foo / vals3 . txt
3 ./ cp_mult . sh foo / vals3 . txt goo / vals3 . txt bar / vals3 . txt
4 echo -e "=== foo / vals3 . txt ==="
5 cat foo / vals3 . txt
6 echo -e "=== goo / vals3 . txt ==="
7 cat goo / vals3 . txt
8 echo -e "=== bar / vals3 . txt ==="
9 cat bar / vals3 . txt
Part #4:
Case #1:
1 echo " old contents to overwrite " > blah . txt
2 ./ run_steps . sh echo 18 27 3 blah . txt
3 cat blah . txt
Case #2:
1 chmod +x do_math . sh
2 ./ run_steps . sh ./ do_math . sh -30 50 10 math_output . txt
3 cat math_output . txt
do_math.sh: (available on Canvas)
1 #!/ bin / bash
2
3 echo " Add 2: "$ (( $1 + 2) )
4 echo " Subtract 1: "$ (( $1 - 1) )
Case #3:
2
1 gcc - Wall - Werror foo .c -o foo
2 ./ run_steps . sh ./ foo 35 115 15 the_output . txt
3 cat the_output . txt
foo.c: (available on Canvas)
1 # include < stdio .h >
2 # include < stdlib .h >
3
4 int main ( int argc , char * argv [])
5 {
6 int num = atoi ( argv [1]) ;
7 if ( num < 50)
8 printf (" Less than 50.\ n ") ;
9 else if (50 <= num && num <= 100)
10 printf (" Between 50 and 100 ( inclusive ) .\ n ") ;
11 else
12 printf (" Greater than 100.\ n ") ;
13 }
5 Your Programming Tasks
In this assignment, you will implement two C functions and two shell scripts. The two C functions go in a file named
prog8.c, and each of the names of the shell scripts is given in the respective part.
Your program should have no memory leaks.
Below is a list of headers that you are allowed to include in prog8.c. You may not need all of these.
• prog8.h
•
•
•
•
•
•
•
5.1 Part #1: getProduct()
In prog8.c, implement a recursive function called getProduct() that takes as arguments an array of integers and the length
of this array. This function should return the product of this array’s values.
No input validation is necessary. (I want you to focus on learning recursion.) Thus:
• arr, as initially provided, will never be NULL. (Depending on your base case(s), it may become NULL.)
• arrLen, as initially provided, is always correct. (When performing a recursive call, be careful to not make arrLen become
incorrect.)
You are not allowed to use a loop for this part, since you must use recursion in a meaningful way. Your
approach should check and potentially act on the first element and then recurse on the rest of the array (i.e. the second
element onwards).
Here is what an implementation of getProduct() would look like if pointer arithmetic were not used. The index would have
to be an argument. You are not allowed to do this, since you are forced to use pointer arithmetic due to the fact that the
two parameters are set (in prog8.h) and you cannot change them. However, this should give you a good starting point.
1 int getProduct ( int * arr , int arrLen , int index )
2 {
3 if ( index == arrLen - 1)
4 return arr [ index ];
5 else
6 return arr [ index ] * getProduct ( arr , arrLen , index + 1) ;
7 }
Cautionary Tip: Be careful about using the prefix/postfix operators. If used improperly, you can encounter a compiler
error message that says something about sequencing. Here is an example to illustrate the concept. The error occurs because
in the line int b = a + ++a;, it is unclear if the left hand side of the addition (i.e. a) should be the old value of a (i.e. 3)
or the new value of a (i.e. 4). With the appropriate compiler flags, this triggers a compiler error. Without these flags, gcc
3
simply makes an assumption about which value of a to use, which is bad, because this is undefined behavior and potentially
inconsistent across different platforms.
1 $ cat main .c
2 # include < stdio .h >
3
4 int main ()
5 {
6 int a = 3;
7 int b = a + ++ a;
8 printf ("% d\n ", b);
9 }
10 $ gcc - Wall - Werror main . c
11 main .c: In function ’main ’:
12 main .c :6:17: error : operation on ’a ’ may be undefined [- Werror = sequence - point ]
13 int b = a + ++ a;
14 ^~~
15 cc1 : all warnings being treated as errors
16 $ gcc main .c
17 $ ./ a. out
18 8
19 $
Below are the test cases that I provide to you on Canvas. assert() takes as argument a boolean (usually a boolean
experssion) and crashes if the expression is false, reporting a diagnostic message if that occurs.
1 $ cat testGetProduct .c
2 # include " prog8 .h"
3
4 # include < assert .h >
5 # include < stdio .h >
6
7 void testGetProduct ( void )
8 {
9 {
10 int arr [] = {5 , 8, 3, -1};
11 assert ( getProduct ( arr , 4) == -120) ;
12 }
13 {
14 int arr [] = { -7 , 14 , -2};
15 assert ( getProduct ( arr , 3) == 196) ;
16 }
17 {
18 int arr [] = {5 , 15 , 0, 100 , -3};
19 assert ( getProduct ( arr , 5) == 0) ;
20 }
21 {
22 int arr [] = {2};
23 assert ( getProduct ( arr , 1) == 2) ;
24 }
25 {
26 int arr [] = {27 , 15 , 3 , 14 , 0 , -5, 2, 0};
27 assert ( getProduct ( arr , 8) == 0) ;
28 // Can " lie " about the array size .
29 assert ( getProduct ( arr , 4) == 27 * 15 * 3 * 14) ;
30 assert ( getProduct ( arr , 2) == 27 * 15) ;
31 assert ( getProduct ( arr , 1) == 27) ;
32 // Demonstrating some pointer arithmetic .
33 assert ( getProduct ( arr + 1, 1) == 15) ;
34 assert ( getProduct ( arr + 1, 2) == 45) ;
35 assert ( getProduct ( arr + 1, 3) == 45 * 14) ;
36 assert ( getProduct ( arr + 5, 2) == -10) ;
37 }
38 fprintf ( stderr , "%s(): All test cases passed !\n", __FUNCTION__ ) ;
39 }
40
41 int main ()
42 {
43 testGetProduct () ;
44 }
45 $ gcc - Wall - Werror -g testGetProduct . c prog8 .c -o testGetProduct
46 $ ./ testGetProduct
47 testGetProduct () : All test cases passed !
48 $
4
5.2 Part #2: linearSearch()
In prog8.c, implement a recursive function called linearSearch() that takes as arguments an array of integers, the length
of this array, and a target integer. This function should return true (i.e. a non-zero integer) if the array contains the target
and false (i.e. zero) otherwise.
No input validation is necessary. (I want you to focus on learning recursion.) Thus:
• arr, as initially provided, will never be NULL.
• arrLen, as initially provided, is always correct.
You are not allowed to use a loop for this part, since you must use recursion in a meaningful way.
Below are the test cases that I provide to you on Canvas.
1 $ cat testLinearSearch . c
2 # include " prog8 .h"
3
4 # include < assert .h >
5 # include < stdio .h >
6
7 void testLinearSearch ( void )
8 {
9 {
10 int arr [] = {5 , 8, 3, -1};
11 assert ( linearSearch ( arr , 4, 8) );
12 assert (! linearSearch ( arr , 4, -7) );
13 assert ( linearSearch ( arr , 4, -1) ) ;
14 assert (! linearSearch ( arr , 4, 50) );
15 }
16 {
17 int arr [] = { -5 , -2 , 2 , -2, 3 , 4 , 1};
18 assert ( linearSearch ( arr , 7, -2) ) ;
19 assert ( linearSearch ( arr , 7, -5) ) ;
20 assert (! linearSearch ( arr , 7, 14) );
21 assert (! linearSearch ( arr , 7, 20) );
22 // Again , we can " lie " about the length .
23 assert (! linearSearch ( arr + 1 , 6 , -5) );
24 assert ( linearSearch ( arr + 1, 6, -2) );
25 assert ( linearSearch ( arr + 1, 6, 2) );
26 assert (! linearSearch ( arr + 3 , 4 , 2) );
27 }
28 fprintf ( stderr , "%s(): All test cases passed !\n", __FUNCTION__ ) ;
29 }
30
31 int main ()
32 {
33 testLinearSearch () ;
34 }
35 $ gcc - Wall - Werror -g testLinearSearch .c prog8 .c -o testLinearSearch
36 $ ./ testLinearSearch
37 testLinearSearch () : All test cases passed !
38 $
5.3 Part #3: Copy to Multiple
Filename: cp_mult.sh
Motivation: Recall that the cp command can be used to copy multiple files into a destination directory, but it cannot be
used to copy one file into multiple destinations. You will write a script that does that.
Write a shell script that takes as argument a regular file (i.e. never a directory) and a list of destinations. The script
should copy the file into each of the given destinations. If not enough arguments are provided, then a usage message should
be printed and the script should return 1 (with exit 1); otherwise, the script should return 0. Note that just like cp, cp_mult.sh
can be used to make multiple copies of a file in the same directory.
Below are some examples of how your script should behave.
1 $ ls d1
2 $ ls d2
3 $ cat vals . txt
4 5
5 18
6 3
7 7
5
8 $ ./ cp_mult . sh vals . txt d1 d2
9 $ echo $?
10 0
11 $ cat vals . txt
12 5
13 18
14 3
15 7
16 $ ls d1
17 vals . txt
18 $ ls d2
19 vals . txt
20 $ ./ cp_mult . sh
21 Usage : ./ cp_mult . sh [ src ] [ dest1 ] ...
22 $ echo $?
23 1
24 $ ./ cp_mult . sh vals . txt
25 Usage : ./ cp_mult . sh [ src ] [ dest1 ] ...
26 $ ls *. txt
27 vals . txt
28 $ ./ cp_mult . sh vals . txt vals2 . txt vals3 . txt vals4 . txt
29 $ cat vals2 . txt
30 5
31 18
32 3
33 7
34 $ cat vals3 . txt
35 5
36 18
37 3
38 7
39 $ cat vals4 . txt
40 5
41 18
42 3
43 7
44 $
5.4 Part #4: Run Steps
Filename: run_steps.sh
Motivation: As a happy undergraduate student, I encountered several situations in which I had to run an executable
multiple times with different command-line arguments and collect the output of each of those runs. As you can hopefully
imagine, doing this manually (i.e. typing each line into the terminal) would have been annoying; you can save time on such
a task by writing a script like the one you will write for this part.
Write a script that takes five arguments:
• A command to run (which could be an executable compiled with gcc). Note that it must be the exact command needed
to run it, not just the executable’s name (which is why you see ./test in the example instead of test).
• A start integer A.
• An end integer B.
• A step integer S.
• An output file.
The script should perform a series of runs of the given command. The first run should have A be passed as argument to
the command to run. In the next run, A + S should be passed. After that, A + 2S, then A + 3S, then A + 4S, and so on,
until the value passed would exceed B. Each run’s results should be logged into the output file. You may not assume this
output file exists, and its old contents should be overwritten.
The script assumes that the executable only takes an integer as its only command-line argument. If not enough arguments
are provided, then a usage message should be printed and the script should return 1 (with exit 1); otherwise, the script should
return 0.
Below are some examples of how your script should behave.
1 $ cat test .c
2 # include < stdio .h >
3
4 int main ( int argc , char * argv [])
5 {
6
6 printf (" Provided : %s \n", argv [1]) ;
7 }
8 $ gcc - Wall - Werror test . c -o test
9 $ ./ run_steps . sh ./ test 10 100 5 output1 . txt
10 $ cat output1 . txt
11 === 10 ===
12 Provided : 10
13 === 15 ===
14 Provided : 15
15 === 20 ===
16 Provided : 20
17 === 25 ===
18 Provided : 25
19 === 30 ===
20 Provided : 30
21 === 35 ===
22 Provided : 35
23 === 40 ===
24 Provided : 40
25 === 45 ===
26 Provided : 45
27 === 50 ===
28 Provided : 50
29 === 55 ===
30 Provided : 55
31 === 60 ===
32 Provided : 60
33 === 65 ===
34 Provided : 65
35 === 70 ===
36 Provided : 70
37 === 75 ===
38 Provided : 75
39 === 80 ===
40 Provided : 80
41 === 85 ===
42 Provided : 85
43 === 90 ===
44 Provided : 90
45 === 95 ===
46 Provided : 95
47 === 100 ===
48 Provided : 100
49 $ ./ run_steps . sh ./ test 50 80 10 output2 . txt
50 $ cat output2 . txt
51 === 50 ===
52 Provided : 50
53 === 60 ===
54 Provided : 60
55 === 70 ===
56 Provided : 70
57 === 80 ===
58 Provided : 80
59 $ cat test2 .c
60 # include < stdio .h >
61 # include < stdlib .h >
62
63 int main ( int argc , char * argv [])
64 {
65 int num = atoi ( argv [1]) ;
66 if ( num < 100)
67 printf (" Less than 100.\ n ") ;
68 else
69 printf (" Greater than or equal to 100.\ n ") ;
70 }
71 $ gcc - Wall - Werror test2 .c -o test2
72 $ ./ run_steps . sh ./ test2 97 104 2 output3 . txt
73 $ echo $?
74 0
75 $ cat output3 . txt
76 === 97 ===
77 Less than 100.
78 === 99 ===
79 Less than 100.
7
80 === 101 ===
81 Greater than or equal to 100.
82 === 103 ===
83 Greater than or equal to 100.
84 $ ./ run_steps . sh ./ test2 97 104
85 Usage : ./ run_steps . sh [ executable ] [ start ] [ end ] [ step ] [ outfile ]
86 $ echo $?
87 1
88 $
8