CSE 101

CSE 101 · WEEK 07 · READING

Software engineering, functions and arrays

Requirements, modularity and evidence—followed by functions and arrays that make a small design concrete.

Read the engineering ideas before tracing the C examples. Try each Check before opening its answer. The final reference sections preserve additional examples from the slides; they are optional. Lab 6 concentrates on one helper and one traversal, with acquisition scaffolding supplied. Wide tables and code scroll sideways on narrow screens.

1. Software belongs to a human activity

A library application does more than calculate a due date. It records who has a book, decides whether another loan is allowed and explains its decision to a person. A student, librarian, administrator and maintainer depend on different aspects of the same system. A program can run without crashing and still fail these people: it might reject a valid loan, lose a record or display a message nobody understands.

A conceptual borrowing situation: understand the people, records and decisions before choosing the software. This is a course-generated illustration, not a photograph of a university service.
Figure 1. A conceptual borrowing situation: understand the people, records and decisions before choosing the software. This is a course-generated illustration, not a photograph of a university service. CSE101 Week 7, slide 2. Source slide.

Software engineering organizes the development and evolution of software systems. It includes understanding needs, designing responsibilities, implementing behavior, gathering evidence and managing changes. Coding is one activity in that larger process. Complexity grows as people, components and operating conditions interact; adding lines of code does not automatically resolve an unclear need.

The library rules in this chapter are hypothetical teaching assumptions. They are not statements of university policy. Using one small example lets us follow a requirement through a design, a function and a test without pretending to implement a complete library system.

Check: The program prints a due date correctly. Has the borrowing system been shown to work?

Only that calculation has been demonstrated under those inputs. Membership checks, book availability, record updates and the user workflow still need evidence.

2. Turn a request into an observable requirement

A stakeholder is someone affected by the system or its development. Their requests often begin informally: “make borrowing easy,” “keep accurate records,” or “make it fast.” A useful requirement states observable behavior and the conditions in which it is expected. This makes disagreements visible before they become expensive implementation changes.

Making the library example testable
Informal requestIllustrative requirement
Handle loans properlyApprove only when the member is active, has fewer than three current loans and the book is available.
Explain a rejectionDisplay the reason and leave the lending records unchanged.
Make it fastShow the result within two seconds under a specified workload and test environment.

A functional requirement describes what the system does, such as recording a successful loan. A quality requirement constrains how well it does it, such as response time or accessibility. Both need evidence. “Within two seconds” remains incomplete until we define the workload, measurement start and end, and acceptable conditions.

Scenarios reveal missing decisions. What happens if the member is active but the book is unavailable? If two people request the last copy nearly together, checking availability and recording the loan must work together. We do not implement concurrency here, but this scenario shows why a correct isolated eligibility calculation cannot establish whole-system correctness.

Check: Why does “reject the fourth loan” need a statement about the stored records?

A rejection message could appear after a record was already changed. The requirement must describe relevant side effects as well as visible output.

3. Correct execution can implement the wrong meaning

Week 6 separated a physical event from its sampled representation. The same distinction becomes a requirements issue. “Count button presses” might mean count samples whose value is 1, count observed transitions from 0 to 1, or estimate distinct physical press events. Those are different tasks.

Logical observations, with 1 meaning pressed
Sample position012345
Value011010

There are three samples equal to 1 and two observed 0-to-1 transitions within this sequence. A held button can produce several pressed samples. Mechanical bounce can produce extra transitions, and a brief press can occur between samples. The meaning of an event at the first sample also depends on the preceding state. Agree on the desired quantity before choosing a loop.

Check: A helper returns 3 for these six values. Is that a defect?

It is correct if the requirement is to count pressed samples. It is not the required result if the task is to count the two observed rising transitions. The requirement determines which answer is correct.

4. Development, use and change

The software life cycle includes repeated maintenance during use. Delivery begins a period of real-world feedback rather than ending all engineering work.
Figure 2. The software life cycle includes repeated maintenance during use. Delivery begins a period of real-world feedback rather than ending all engineering work. CSE101 Week 7, slide 5. Includes a Brookshear textbook figure retained in the course slides. Source slide.

A system changes because faults are discovered, policies change or its environment changes. A new operating system, storage service or input device can invalidate an earlier assumption. Maintenance therefore includes changing requirements, tests and documentation as well as implementation.

A traditional staged development model identifies requirements, design, implementation and testing. The activities remain useful even when the work revisits them repeatedly.
Figure 3. A traditional staged development model identifies requirements, design, implementation and testing. The activities remain useful even when the work revisits them repeatedly. CSE101 Week 7, slide 11. Includes a Brookshear textbook figure retained in the course slides. Source slide.

Iteration revisits a solution using feedback. Incremental development adds usable portions: loans first, then returns and renewals. A prototype might test whether users understand a rejection message before the real record-storage service exists. A successful demonstration does not establish that persistence, failures or simultaneous use have been handled.

Check: A team revises its requirements after showing a paper prototype. Has it necessarily failed to plan?

No. The prototype may have exposed an assumption early. Record what changed and carry the clarification into the design and tests. Iteration still requires disciplined decisions.

5. Divide responsibilities and explain the connections

A structure chart for a tennis-game simulation. It organizes component relationships; unlike a flowchart, it does not specify every decision and execution order.
Figure 4. A structure chart for a tennis-game simulation. It organizes component relationships; unlike a flowchart, it does not specify every decision and execution order. CSE101 Week 7, slide 14. Includes a Brookshear textbook figure retained in the course slides. Source slide.

Decomposition divides a system into responsibilities that can be explained separately. For the library, an eligibility component decides whether a member qualifies; an availability component checks the copy; a coordinator arranges a successful update; and a presentation component explains the result. A component can contain several functions, so decomposition is useful at more than one scale.

Cohesion concerns how closely a component’s responsibilities belong together. Keeping eligibility rules together makes a policy change easier to locate. Coupling concerns dependencies between components. If the display directly edits lending records, a visual change can unexpectedly affect the data. Letting it receive a decision through a defined interface reduces that dependence on internals.

A good division is not simply “as many tiny functions as possible.” Too many poorly named fragments can obscure the task. Choose boundaries that give each part a purpose and make the relationships understandable. Ask what information a caller really needs to know and what changes the component should be able to absorb.

Check: Does the structure chart mean Serve, Return, ComputePath and UpdateScore always execute once in that left-to-right order?

No. It shows the organization of responsibilities. To describe ordering, decisions and repetition, inspect the algorithm or draw a flowchart.

6. Interfaces, contracts and information hiding

An interface says how another component is used. A contract explains the meaning: valid inputs, promised results and allowed side effects. A function’s types alone rarely express all of these rules. An integer parameter called loans still needs a statement about whether negative values are allowed.

A small eligibility contract
PartAgreement
Inputsactive is 0 or 1; loans is a nonnegative count.
ResultReturn 1 exactly when active is 1 and loans is less than 3; otherwise return 0.
Side effectsDo not change lending records.
BoundaryThis helper does not check book availability or perform a loan.

Information hiding keeps internal decisions behind an interface. A record service could change its storage representation while preserving the operations other components use. Callers then depend on the agreed behavior rather than the storage layout. Compatibility still matters: changing the meaning of a return value breaks a contract even if the parameter types stay the same.

Preconditions are obligations, not automatic checks. The eligibility helper below trusts that the caller supplied a nonnegative count. If corrupted input is possible, an input-validation layer must reject or handle it according to an explicit rule. Writing a precondition in a comment does not cause C to enforce it.

Check: If the eligibility helper returns 1, may the caller immediately assume that a book has been issued?

No. It has only checked member eligibility. Availability and successful record updating are separate responsibilities. The name and contract should make that boundary clear.

7. Reuse and the Ariane 501 case

Reusing a component also reuses its assumptions about ranges, timing, interfaces and failure responses. A component that worked in one environment needs evidence for the new environment. A backup that shares the same vulnerability may fail under the same conditions.

Ariane 501 on its launch pad. Photograph: CSG for ESA/CNES, retained from ESA Bulletin 89.
Figure 5. Ariane 501 on its launch pad. Photograph: CSG for ESA/CNES, retained from ESA Bulletin 89. CSE101 Week 7, slide 20. Source slide.

ESA describes the 1996 Ariane 501 failure as a loss of guidance information following software specification and design errors in the inertial reference system. A pre-launch alignment function remained active during flight; a value exceeded its representable range, and the malfunction response shut down the processor. Both reference systems failed. The investigation also found inadequately identified interfaces and tests that did not sufficiently represent flight conditions. See de Dalmau and Gigou’s ESA account.

The engineering lesson is broader than “choose a larger integer.” Review why a computation is active, what values its environment can produce, how failure is reported and how dependent parts react. Testing a component alone and duplicating it do not establish that its integration will tolerate the actual failure mode.

Check: Why can two identical tested components still fail together?

They can share an assumption that the new environment violates. Duplication protects against some independent faults, but does not automatically protect against a common design defect.

8. Verification, validation and test levels

Verification asks whether the implementation meets the stated rules. Validation asks whether the system and its rules serve the intended need. For example, tests can verify rejection at three loans, while librarians review whether that policy and workflow are appropriate. Both kinds of work can begin before a final program exists, through reviews, models and prototypes.

Evidence at different levels
LevelLibrary example
UnitCall the eligibility function with selected active/count pairs.
IntegrationCheck that the coordinator uses the decision correctly and updates the records only on success.
SystemRun the complete borrowing workflow, including storage and messages.
AcceptanceHave stakeholders evaluate agreed realistic scenarios for intended use.

A test needs an initial state, input, expected result and observation. Derive the expected result independently from the requirement; copying whatever the program currently prints gives it permission to be wrong. For rejection, inspect both the message and the unchanged records. An output-only check can miss an unwanted side effect.

NASA’s requirements-validation guidance provides a professional example of reviewing requirements for qualities such as clarity and consistency. Here it is further reading about engineering reasoning, not a NASA compliance process imposed on the course.

Check: All unit tests pass, but the user sees success when record storage fails. Which additional evidence is needed?

Integration and system checks must cover the interaction and failure path. A correct local decision does not guarantee successful storage or correct presentation.

9. Select tests that can expose mistakes

Black-box testing selects cases from the specified behavior without relying on the implementation. White-box testing uses the implementation’s branches or paths to identify cases. These views complement each other. Executing each statement once can miss a wrong threshold, an omitted requirement or an interaction between inputs.

Loan boundary cases: active member, available book
Current loansExpected decisionReason
0ApproveClearly below the limit.
2ApproveImmediately below the limit.
3RejectExactly at the limit.
4RejectAbove the limit.

Also test an inactive member, an unavailable book and the handling of invalid input at the layer responsible for validation. Twenty independent binary inputs already give 2²⁰ = 1,048,576 combinations. Meaningful categories and boundaries help allocate testing effort, but selected passing tests do not prove the absence of all defects.

A useful defect report states the version, initial conditions, reproduction steps, expected behavior and observed behavior. After repairing a fault, retain a regression test that would fail if it returned. A test such as “three current loans must be rejected” is more informative than “the program ran.”

Check: A test with zero loans passes even when the implementation mistakenly uses loans ≤ 3. Which case reveals that defect?

Exactly three loans. Both expressions agree at zero, but the inclusive comparison incorrectly approves at the boundary.

10. Make a policy change traceable

Suppose the example loan limit changes from three to five. The code is only one affected artifact. Update the requirement, boundary examples, tests and user explanation. A small traceability record connects a rule to its design location and evidence, making these effects easier to find.

Change review for a limit of five
ItemReview
Requirement and decisionReplace the old limit with the approved new one.
Boundary evidenceTest four, five and six current loans.
Unchanged behaviorInactive members still fail; rejection still preserves records.
ExplanationMessages and documentation use the same policy.

Version control records revisions and supports comparison and review. A useful change description explains why behavior changed, not just which file was edited. Version history and backups serve related but different purposes: history supports reasoning about changes; backups help recover data after loss. Neither replaces testing the changed behavior.

Check: Would changing every 3 in the project to 5 be a sound maintenance method?

No. Other occurrences may describe array sizes, unrelated rules or historical examples. Follow the requirement’s dependencies, make the intended change and check both changed and preserved behavior.

11. A function gives a computation a name

A function packages a responsibility behind a name and an interface. The caller supplies arguments; the function gives them local names called parameters. A return value can carry the result back to the caller. This is a small-scale form of the modular design discussed earlier.

The instructor’s tea-making example: a familiar task can be named, understood and reused.
Figure 6. The instructor’s tea-making example: a familiar task can be named, understood and reused. CSE101 Week 7, slide 35. Source slide.
The original tea-making flowchart. Follow the decisions and waiting loops; naming the task does not remove its internal algorithm.
Figure 7. The original tea-making flowchart. Follow the decisions and waiting loops; naming the task does not remove its internal algorithm. CSE101 Week 7, slide 36. Source slide.

A caller can ask for tea without reciting the full procedure each time. The analogy also exposes a contract: how many cups, which ingredients and what counts as completion? In software, a meaningful name reduces repetition only when its behavior is agreed. A function may compute a value, perform an output operation, or both; make side effects explicit.

Library and user-defined functions. The original DLL wording is platform-specific; a C library is not necessarily distributed as a Windows DLL.
Figure 8. Library and user-defined functions. The original DLL wording is platform-specific; a C library is not necessarily distributed as a Windows DLL. CSE101 Week 7, slide 37. Source slide.

Functions such as printf come from a library; canBorrow is our own function. Headers provide declarations, while implementations are supplied by source or libraries during the build. Libraries may be linked in different ways, as discussed in Week 5.

Check: Does putting a long unclear task inside a function automatically make the design modular?

No. The function needs a coherent responsibility, understandable inputs and a clear result or effect. Naming a confusing block can conceal rather than resolve its design problems.

12. Parameters, return values and scope

The original function anatomy: result type, name, parameters, local declaration, computation and return statement.
Figure 9. The original function anatomy: result type, name, parameters, local declaration, computation and return statement. CSE101 Week 7, slide 38. Source slide.
#include <stdio.h>

int canBorrow(int active, int loans) {
    return active && loans < 3;
}

int main(void) {
    printf("%d\n", canBorrow(1, 2));
    printf("%d\n", canBorrow(1, 3));
    printf("%d\n", canBorrow(0, 0));
    return 0;
}

The three results are 1, 0 and 0 on separate lines. In the first call, active receives 1 and loans receives 2. The logical expression is true and returns 1. Each call uses the same body with different input values. The contract excludes negative loan counts; this short function does not validate them or check availability.

A return value becomes available to the caller. Correction to the original green note: C does not require every returned value to be stored in a variable.
Figure 10. A return value becomes available to the caller. Correction to the original green note: C does not require every returned value to be stored in a variable. CSE101 Week 7, slide 40. Source slide.

A returned value can be assigned, used directly inside another expression, or deliberately ignored. In our program it is passed straight to printf. A void function returns no value. A declaration tells the compiler the function’s types; a definition additionally supplies its body. Defining a function before its first call is sufficient for these examples.

Ordinary scalar parameters receive values. In void change(int value) { value = 99; }, the assignment changes the local parameter. Calling change(x) with x = 4 leaves the caller’s x equal to 4. A local name is visible within its scope; an ordinary automatic local object belongs to that invocation. Clear parameters and results reduce dependence on shared global state.

Check: Can canBorrow(1, 2) be used directly as an if condition?

Yes. Its integer result can be tested without an intermediate variable. That still establishes only eligibility, according to its contract.

Check: Two functions both declare a local variable named count. Do they necessarily share one count?

No. The local declarations designate separate objects. Sharing a spelling does not make the objects the same.

13. Arrays: positions, elements and values

An array holds a fixed number of elements of one type in consecutive storage. An index selects an element; it is not the value stored there. Six elements have C indices 0 through 5. The last valid index is one less than the length.

Six consecutive elements. The original picture labels positions 1–6; C uses indices 0–5 for those positions.
Figure 11. Six consecutive elements. The original picture labels positions 1–6; C uses indices 0–5 for those positions. CSE101 Week 7, slide 45. Source slide.
An array, its four elements and their indices. For length four, the first index is 0 and the last is 3.
Figure 12. An array, its four elements and their indices. For length four, the first index is 0 and the last is 3. CSE101 Week 7, slide 46. Source slide.
int samples[6] = {0, 1, 1, 0, 1, 0};
int first = samples[0];
samples[3] = 1;

The first assignment to first copies the value 0. The next statement changes the fourth element, producing 0, 1, 1, 1, 1, 0. Each later example in this reading begins again with the original six values unless stated otherwise. A copied scalar does not automatically track later array changes.

Array declaration and initialization. The C declaration initializes balance with 300, 200 and 100; remember its final semicolon. The Python illustration uses its array module.
Figure 13. Array declaration and initialization. The C declaration initializes balance with 300, 200 and 100; remember its final semicolon. The Python illustration uses its array module. CSE101 Week 7, slide 49. Source slide.
balance[1] selects the second element, containing 200. The index 1 and the value 200 play different roles.
Figure 14. balance[1] selects the second element, containing 200. The index 1 and the value 200 play different roles. CSE101 Week 7, slide 51. Source slide.

An automatic local array declared without initialization does not supply usable initial element values. int values[6] = {0}; initializes all six to zero. C does not automatically check every index. Reading or writing outside the array has undefined behavior; apparently plausible output cannot establish that an out-of-bounds access is safe.

Check: For int balance[3] = {300, 200, 100}, what are balance[2] and balance[3]?

balance[2] is 100. balance[3] is outside the array and must not be accessed. It is not a fourth element containing zero.

14. More dimensions, the same need for bounds

A two-dimensional array uses row and column indices, each beginning at zero.
Figure 15. A two-dimensional array uses row and column indices, each beginning at zero. CSE101 Week 7, slide 52. Source slide.

A declaration such as int grid[2][3] describes two rows of three integers. grid[1][2] is the third element of the second row. Both dimensions have bounds: valid row indices are 0–1 and column indices 0–2. A table-shaped view is useful for coordinates even though physical memory is a sequence of locations.

Row-major and column-major layouts compared. An actual C multidimensional array uses row-major order: complete one row before the next. Both original image components are retained.
Figure 16. Row-major and column-major layouts compared. An actual C multidimensional array uses row-major order: complete one row before the next. Both original image components are retained. CSE101 Week 7, slide 53. Source slide.

For int grid[2][3] = {{10, 11, 12}, {20, 21, 22}};, the consecutive element values are 10, 11, 12, 20, 21, 22. The rightmost index varies fastest. This describes an actual C array of arrays; later pointer-based structures need not have the same storage arrangement.

The original three-dimensional illustration. Some labels in its bottom row repeat incorrectly; use the corrected C ordering in the text when tracing indices.
Figure 17. The original three-dimensional illustration. Some labels in its bottom row repeat incorrectly; use the corrected C ordering in the text when tracing indices. CSE101 Week 7, slide 54. Source slide.

For a C array a[2][2][3], the first six locations are a[0][0][0], a[0][0][1], a[0][0][2], a[0][1][0], a[0][1][1], a[0][1][2]. Then the first index advances to 1. The supplied illustration helps visualize dimensions, but its repeated labels should not be memorized as an address rule. Extended multidimensional practice comes later; our helper processes one dimension.

Check: How many integers are in grid[2][3], and is grid[2][0] valid?

There are six integers. grid[2][0] is invalid because row index 2 is outside the two rows, even though column index 0 is valid.

15. Give an array helper an explicit contract

The array helper receives logical samples and a count n. With the original six values and n = 6, it returns 3.
Figure 18. The array helper receives logical samples and a count n. With the original six values and n = 6, it returns 3. CSE101 Week 7, slide 55. Source slide.

countPressed counts samples equal to 1 among the first n elements. Require 0 ≤ n ≤ available length, with examined values restricted to 0 or 1. The result is the count; the helper leaves the input unchanged. With n equal to zero, no elements are examined and the answer is zero. This can be tested using an ordinary allocated array and requesting an empty prefix.

In a C parameter, const int samples[] provides access to the caller’s elements; it does not copy the whole array. The function also needs n because that parameter does not retain the caller’s array length. Under C’s rules the array parameter is adjusted to a pointer parameter. Pointer details come later, but the practical contract matters now.

const prevents this function from writing elements through that parameter. It does not create a copy, check bounds or make the entire original array immutable everywhere. Ordinary C arguments still pass values: in this case the passed value provides access to existing elements. See the GNU C manual’s functions and array-parameter discussion.

Check: If the available array has six elements, is calling countPressed(samples, 10) protected by the loop’s i < n test?

No. The loop obeys the supplied n, so it would attempt to read beyond the six available elements. The caller must supply a valid length; this helper cannot discover it from the parameter.

16. Trace the traversal and explain why it works

The No branch at samples[i] == 1 bypasses the increment of count. Both paths advance i and return to the bounds test, not initialization.
Figure 19. The No branch at samples[i] == 1 bypasses the increment of count. Both paths advance i and return to the bounds test, not initialization. CSE101 Week 7, slide 58. Source slide.
#include <stdio.h>

int countPressed(const int samples[], int n) {
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (samples[i] == 1) {
            count++;
        }
    }
    return count;
}

int main(void) {
    int samples[6] = {0, 1, 1, 0, 1, 0};
    printf("%d\n", countPressed(samples, 6));
    return 0;
}
Trace with n = 6
i before bodysamples[i]count after body
000
111
212
302
413
503

After the final update, i becomes 6. The condition is false, so no element at index 6 is read; the function returns 3. With n = 3, only indices 0, 1 and 2 are examined, yielding 2. With n = 0, the body never executes and count remains zero.

A loop invariant is a useful statement preserved as the loop advances. Here, before each iteration, count equals the number of ones among the first i elements. It is initially true for zero elements. Examining the next value and incrementing only for 1 extends the statement to the next prefix. When i reaches n, it describes all requested elements. Progress of i toward n explains termination under the contract.

Check: What breaks if count = 0 is moved inside the loop body?

The accumulated result is reset for every element. The loop no longer remembers how many earlier elements matched, so the stated invariant fails.

17. Test the contract and its boundaries

Independent expected results
Examined datanExpected
Empty prefix of an allocated array00
010
111
0, 0, 0, 040
1, 1, 1, 144
0, 1, 1, 0, 1, 063
First three of the mixed array32

Check input preservation as well as the returned number. This matters because a helper might produce the right answer while accidentally modifying a sample. Testing a prefix also reveals a helper that ignores n and always processes six elements.

Changing i < n to i <= n attempts one extra access. If the requested prefix is shorter than the allocation, the error may remain inside allocated storage but count an unwanted element. If n equals the allocation length, the extra access is out of bounds. Starting count at 1 produces another fault: the empty prefix already gives the wrong answer.

Check: Why is n = 0 useful even though there is no zero-length C array in this example?

The array exists; the request is to examine zero of its elements. The case tests the loop’s entry condition and the result’s initial value without requiring a zero-length array declaration.

18. Separate acquisition, computation and reporting

For Lab 6, use one helper and one traversal. Fixed logical samples isolate the computation from electrical wiring, input timing and switch bounce. A logical 1 means pressed after normalization; a physical input level may use a different convention. Acquisition scaffolding belongs to the lab plan, not to an extra requirement introduced by this reading.

int countPressed(const int samples[], int n) {
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (samples[i] == 1) count++;
    }
    return count;
}

void setup() {
    Serial.begin(9600);
    int samples[6] = {0, 1, 1, 0, 1, 0};
    Serial.println(countPressed(samples, 6));
}

void loop() {}

This Arduino C++ sketch requests serial communication at 9600 baud and prints 3 once during setup. Match the Serial Monitor setting. Resetting the board repeats setup. The empty loop supplies no additional output. A passing fixed-data example demonstrates the helper and reporting path, not that a physical button has been sampled correctly.

Check: Should this sketch’s output be labelled “three physical button presses”?

No. It represents three pressed samples in a fixed data set. Physical event counting needs a separate definition and suitable acquisition evidence.

19. Optional reference: an array of digit counters

The original digit-counting example. Its historical implicit-int main spelling is not modern C; use an explicit int main(void) in a new program.
Figure 20. The original digit-counting example. Its historical implicit-int main spelling is not modern C; use an explicit int main(void) in a new program. CSE101 Week 7, slide 71. Source slide.

An array can hold counters indexed by categories. Ten counters represent digits 0–9. After confirming that a character c lies between '0' and '9', the expression c - '0' yields the matching index. C guarantees consecutive codes for these decimal digits; the idea does not require hard-coding ASCII value 48.

The supplied example output lists ten digit counts, then whitespace and other-character counts. It is historical output for its own input, not the output of the new example below.
Figure 21. The supplied example output lists ten digit counts, then whitespace and other-character counts. It is historical output for its own input, not the output of the new example below. CSE101 Week 7, slide 72. Source slide.
The original character-code table illustrates adjacent digit codes. Character symbols and their numeric values are different representations.
Figure 22. The original character-code table illustrates adjacent digit codes. Character symbols and their numeric values are different representations. CSE101 Week 7, slide 73. Source slide.

For input 2012 a followed by a newline, digits 0, 1 and 2 occur once, once and twice. Space and newline contribute two whitespace characters to the original rule; a contributes one other character. A stream-reading version keeps the result of getchar() in an int so it can distinguish a character value from EOF. This is an optional illustration of indexed counters, not a new required input-processing assignment.

Check: Why must the digit test happen before using c - '0' as an array index?

For a non-digit, the difference is not guaranteed to be between 0 and 9. The category test establishes the valid-index condition before access.

20. Optional reference: read older diagrams critically

The original swap illustration uses pass-by-reference pseudocode. It is not the behavior of ordinary scalar C parameters.
Figure 23. The original swap illustration uses pass-by-reference pseudocode. It is not the behavior of ordinary scalar C parameters. CSE101 Week 7, slide 74. Source slide.

The pseudocode’s in/out parameters denote access to the caller’s variables. By contrast, swap(int x, int y) in C receives scalar values and changing them does not swap the caller’s variables. Later pointer examples will show how C can deliberately access caller-owned objects. Keep the diagram’s convention separate from the rules of the language being used.

Historical call-and-return illustration retained from the instructor’s source. It is an archive reference, not a new assembly or simulator exercise.
Figure 24. Historical call-and-return illustration retained from the instructor’s source. It is an archive reference, not a new assembly or simulator exercise. CSE101 Week 7, slide 75. Source slide.

At a conceptual level, a call must allow execution to continue in the caller afterward, and an implementation must manage any needed temporary state. Exact instructions and calling conventions vary. This historical image provides context; Week 7 explanations and activities use C and Arduino C++.

Check: Can a diagram with the word parameter be assumed to show C pass-by-value behavior?

No. Read the notation and stated convention. Pseudocode may deliberately use a different model, as the swap diagram does.

21. Further study and what to carry forward

Be able to connect a requirement to a component contract and an independent test. Explain the difference between a structure chart and a flowchart, trace scalar arguments and returns, distinguish an array index from its stored value, and justify a bounded traversal. Week 8 develops the next question: how algorithms behave as input size grows, including searching and sorting.

  • Brookshear and Brylow, Computer Science: An Overview, 12th Global Edition (2015), Chapter 7: life cycle, modularity, quality assurance and documentation. Figures 2–4 retain textbook Figures 7.1, 7.2 and 7.3, printed pages 335, 336 and 341.
  • NASA: requirements validation. Read for the questions a reviewer asks about a requirement; do not treat the agency process as a course assignment.
  • ESA: learning from Ariane flight 501. Relate the failure analysis to operating assumptions, failure response and representative tests.
  • GNU C Language Introduction and Reference Manual. Consult Functions and Arrays; distinguish standard C examples from explicitly identified GNU extensions.
  • Arduino array reference and Serial reference. Compare array bounds and output operations with the supplied fixed-data sketch.

The reading retains the current deck’s teaching images, including the instructor’s original function and array figures and their embedded credits. Source links accompany each figure. Figures 1, 18 and 19 are course-generated conceptual illustrations. Historical images with one-based labels, outdated syntax or different parameter conventions are explained alongside their modern C interpretation. Complete practice belongs in recitation and lab; this chapter supplies concepts, predictions and small worked examples.

Search courses