Unit 2 · Lesson 118 minAcademic review pending

Building on what already exists

Most programs are edits of programs that already work. Learn to start from existing information and from the C library instead of from an empty file.

Choose explanation

After this lesson

You should be able to

  • Turn a problem statement into a data requirements list before writing code.
  • Call standard library functions such as sqrt, pow, fabs and abs correctly.
  • Explain why a library function needs both a header and, sometimes, a linker flag.
01

Start from the data, not the code

Before writing a line, list three things: what you are given, what you must produce, and what you need in between. For a circle problem you are given the radius, you must produce area and circumference, and in between you need the constant pi. That list becomes your declarations almost word for word.

This is not a formality. Most first-year bugs are not syntax errors — they are a missing input or a value the program never computed. A requirements list makes those visible before the compiler ever runs.

The requirements list becomes the declarations
/* Given:    radius
   Produce:  area, circumference
   Between:  PI                    */

#define PI 3.14159

double radius, area, circumference;
02

The library has already solved it

C ships with tested functions for common mathematics. sqrt(x) gives a square root, pow(x, y) raises x to the power y, fabs(x) gives the absolute value of a double, and abs(n) does the same for an int. Writing your own square root is not resourceful; it is slower, less accurate, and untested.

Each family lives in a header. Maths functions need #include <math.h>. Miss the header and the compiler assumes the function returns an int, which quietly truncates your answer instead of failing loudly.

Three library calls, one header
#include <stdio.h>
#include <math.h>

int main(void)
{
    double x = 2.0;

    printf("%.4f\n", sqrt(x));      /* 1.4142  */
    printf("%.4f\n", pow(x, 10));   /* 1024.0000 */
    printf("%.4f\n", fabs(-7.5));   /* 7.5000  */

    return 0;
}
03

Read the function's contract

Every library function has a contract: what types it takes, what type it returns, and what inputs are legal. sqrt expects a non-negative double. Passing a negative value is not a crash — it returns a special not-a-number value that then poisons every calculation it touches.

So guard the input rather than the output. Test x >= 0 before calling sqrt, instead of trying to detect the strange result afterwards.

Try it yourself

Read the three coefficients of a quadratic equation and print its two real roots, refusing politely when the roots are not real.

Need a hint?

Compute the discriminant first and test it before you call sqrt.

Check the worked solution

The discriminant b*b - 4*a*c decides everything, so it is computed once and tested before sqrt ever sees it — that is guarding the input rather than inspecting a strange output. Note 2 * a is written as a double expression; if a were an int and you wrote (-b + root) / 2 * a, precedence would divide first and then multiply, which is a different formula entirely.

#include <stdio.h>
#include <math.h>

int main(void)
{
    double a, b, c, disc, root;

    printf("Enter a, b, c: ");
    scanf("%lf %lf %lf", &a, &b, &c);

    if (a == 0) {
        printf("Not a quadratic equation.\n");
        return 1;
    }

    disc = b * b - 4 * a * c;

    if (disc < 0) {
        printf("Roots are not real.\n");
        return 0;
    }

    root = sqrt(disc);
    printf("x1 = %.4f\n", (-b + root) / (2 * a));
    printf("x2 = %.4f\n", (-b - root) / (2 * a));

    return 0;
}

Quick check

You call sqrt but forget #include <math.h>. What is the most likely result?

Select an answer to check your thinking.

Why this lesson exists

Syllabus mapping

Building Programs from Existing Information · Library Functions

Maps to course outcomes CO2, CO3.