Imma be totally honest with you: the thing you're about to read was not meant to be a "side read" =))
Hence the inhumane amount of information and the length (close to 130k characters...20ksomething words) of this material. Initially this was supposed to be the whole lecture =).
The way I first envisioned this was that CS1 would be like a fairly tale, a whole story that walks you through what it meant to develop this field...the sheer amount of human intervention it took to make fancy rocks we call "Silicone" behave under electricity and perform calculations.
As it turns out, "socoteala din targ nu da cu aia de acasa" and I had to basically redo the whole course
But if you're the type that likes to read, I beg you to cast an eye on this too, it'll (hopefully) give you a new kind of appreciation for the field of Computer Science, for computers as a whole and for what it means to be a "Computer Engineer" not just a programmer.
Ahead of you lay 30 hours of arduous work which come to a total of about 2-3 hours of reading for you. Enjoy!
Last time, we did electronics. From the ground up (literally talking the whole course in terms of electrons, flow, deriving all the "laws" logically, along with discussing why we have the quotation marks around the word laws and many more concepts).
Today's reading/lecture (depending on the format that you receive it in) will be a little different. We will still take this really "grounded" approach and build upon things.
But without much of the more "hardcore" digital electronics part that you will learn in the following course (That being E2).
So...what's the aim for CS1?
CS1 is one of the dearest forms of education to me. Introducing Computer Science opens a lot of gates in terms of what could be discussed.
As such CS1 aims to be more like a "walk-through" along the history of computation and computers.
CS1 will tell a story of how our innate tendency for stability and prediction made us do what is essentially just convinving really pure rocks to do calculations for us =)) .
It is a story of tragedy, of human error, of untapped potential and of identities. I want you to meet some of the pioneers of this great field before you make the big leap into it.
Afterall, what makes us human if not those stories? The stories that inspire. Stories, not of celebrated heroes that slay dragons but of unsung ones that helped us avoid, perhaps, doom, annihilation and aided in preserving the values of human dignity as we know it. They're stories of wars, hatred, friendship, early death, divorces and much more.
This is introduction to Computer Science!
Right. I just spent a whole section getting misty-eyed about tragedy, human dignity and unsung heroes, so let me come back down to earth and tell you, concretely, what you walk out of here knowing. Because this is still a real course =)).
Here's the frame I want you to hold onto for the whole lesson: right now, the computer in front of you is a magic box (a very fancy arrangement of those "pure rocks" I mentioned a second ago). You press keys, things happen, and (be honest) you have no real idea why. That is not a knock on you, it is literally what the thing is designed to feel like. Hiding the internal machinations is the entire point of a good computer, and we'll talk a LOT about that hiding (it has a name: abstraction). But here's the line between a user and an engineer: for an engineer, the box gets to stay magic only as a choice, never because they're stuck. By the end of CS1, you should be able to crack the lid, point at each piece in there, and go "ah, right, that's the bit that does that."
This course has two halves that look like completely different subjects but are secretly the same story told twice.
The first half is just: "how on earth did we end up with a magic box at all?" We retrace the whole lineage, roughly in the order it actually happened:
The second half is: "okay, now YOU tell the box what to do." And this is where the "same story twice" thing clicks into place, because the code you write is going to sit right on top of that exact architecture you just took apart. We cover:
Now, some honesty about what we are NOT doing (E1 people already know I do this on purpose):
And exactly like in E1, you will not just be reading. You'll get your hands on little simulators and online compilers: you'll watch a tiny program crawl through a CPU one step at a time, watch your C transform into raw assembly live as you type it, and watch your variables pop into memory as each line runs. Play with them. Poke them. That is where this stuff actually sinks in, not in the paragraphs.
To round it off, your very first assignment, and it's the same flavor of trap as the "define a resistor" question from E1:
Exercise: Explain, in complete detail, everything that happens between the moment you press the 'A' key on your keyboard and the moment the letter A appears on your screen. Every single step. Go as deep as you possibly can, and pay very close attention to exactly where you get stuck.
Got an answer? Good. Keep it somewhere. We are going to circle all the way back to it at the very end of the course and watch you take it apart properly, step by step.
For now, let's start where the whole story started: not with a computer, not even with electricity, but with math.
This whole ordeal (CS1 + CS2+ CS3) is based on Ritchie (may his soul rest in peace) & Kernighan's "The C Programming Language" textbook. Those are the people that made the language, y'know. And one of the has some really kind words for all of you:
Before any machine, before electricity, before a single rock got talked into performing fast multiplicaton, computing began as an idea. A purely mathematical one. And it begins with a name you already know, you just don't know that you know it.
Around the year 820, in the House of Wisdom in Baghdad, a Persian scholar named al-Khwarizmi wrote a book called Al-Jabr (roughly translated to "The Concise Book of Calculation by Restoration and Balancing"), you can find a translation here about solving equations through fixed, step-by-step procedures. Centuries later his name was carried into Latin as Algoritmi, and those step-by-step procedures carried his name with them. That is the word algorithm: every single time you say it, you are saying a slightly mangled version of a 1200-year-old man's name. And it gets better, because the book's title contained the words al-jabr. Latinize that and you get algebra. One scholar, two words you have been using since middle school without the faintest clue where they came from.
Fun fact: al-jabr didn't originally mean anything mathematical. It meant roughly "the reuniting of broken parts", and was also the everyday word for setting a broken bone. For centuries in Spain, a barber-surgeon who reset fractures was called an algebrista. So next time algebra breaks you, take comfort: linguistically, it was always supposed to put you back together.
But what al-Khwarizmi really planted was an idea so plain-sounding that its weight is easy to miss: that solving a problem can be reduced to following a recipe. A fixed list of unambiguous steps that, even if you follow them blindly with zero understanding of why, still cough up the correct answer. Hold tight to that word: mechanically. Because if a procedure is genuinely mechanical (no insight, no creativity, no human judgment needed at any step) then a rather cheeky question follows: does it even need a human?
It took the better part of a thousand years for someone to ask that out loud and truly mean it. That someone was Gottfried Wilhelm Leibniz (yes, the same Leibniz a few of you will eventually meet, and fight with, in calculus). Leibniz did three things that land him squarely in our story. He built a brass calculating machine, the Stepped Reckoner (here is a beautiful replica), that could add, subtract, multiply and divide just by turning a crank. He also worked out binary in 1703: the realization that you need only TWO symbols, 0 and 1, to write any number that exists (sound familiar? it's the only language those rocks we call processors nowadays will speak, and we'll come back to it). And biggest of all, he dreamed of a day when human reasoning itself could be boiled down to calculation, so that two people stuck in a bitter argument could simply sit down, pick up their pens, and settle it by computing the answer. He even had a battle cry for it: "Calculemus!" -> "Let us calculate!"

Sit with how wild that is. Leibniz didn't only dream that arithmetic could be done by a machine. He dreamed that thinking could. He just had the catastrophic bad luck of being roughly 250 years too early, with no technology on Earth capable of building the thing he was describing.
But a dream stays a dream until somebody is stubborn enough to forge it in metal. And the first person mad enough to try, a full century before the world was anywhere near ready, built his would-be computer out of brass and gears.
The man mad enough to try was Charles Babbage. English, born in 1791, mathematician, and by nearly every account a brilliant, prickly, **perpetually-frustrated ** human being who picked fights with almost everyone (including, eventually, the entire concept of street musicians, but that's a story for another day =))) ).
To get why he did what he did, you need the problem he was staring at, and it's a problem with a body count. Back then, all the mathematical tables society leaned on (logarithms, tables for navigation at sea, astronomical tables, interest tables for banks) were worked out by hand. By people. In fact, the job had a name, and the name : those people were called computers. That's right, "computer" was originally a job title for a human being (maybe clanker used to mean something different before too?), somebody whose entire profession was grinding through arithmetic all day. Hold onto that, because we are going to meet rooms full of human computers again later, in a far darker chapter.
But the fancy monkeys with clever thumbs we call humans make mistakes. A computer copies a digit wrong, the typesetter sets it wrong, a single wrong number in a navigation table and a ship full of people can sail straight onto rocks. The tables were riddled with errors, and the errors were expensive and sometimes lethal. Babbage, checking a stack of error-laden tables with his friend John Herschel and growing more disgusted by the minute, is supposed to have burst out: "I wish to God these calculations had been executed by steam." Half a joke. Half a manifesto. Why trust a tired, error-prone human to turn a crank when a machine could turn it perfectly, every time, forever?
So he designed one such machine. The Difference Engine was a giant, hand-cranked, brass calculating machine built to compute those tables flawlessly and, crucially, to print them itself, cutting the error-prone human out of both the calculating AND the typesetting. It pulled off this trick using a clever method (the "method of finite differences", hence the name) that turns the whole job into nothing but repeated addition, no multiplication needed, which is exactly the kind of dumb-but-relentless task a machine of gears is perfect for.
It was an absolute monster: thousands of precision-machined parts, tons of brass. The British government, smelling accurate naval tables, poured in funding (a genuinely staggering sum for the era, comparable to the cost of a couple of warships). Babbage started in 1823. And then... he didn't finish it. He fell out spectacularly with his chief engineer, the money dried up, and his attention started drifting toward something far bigger. He built a working fragment, enough to prove the principle, and it dazzled everyone who saw it. But the complete Difference Engine never came together in his lifetime.
Here is how it looked:

Fun fact (and a glorious vindication): people quietly assumed for over a century that Babbage's design was a beautiful fantasy that could never actually have worked. So in 1991, for the 200th anniversary of his birth, the London Science Museum decided to settle it: they built Difference Engine No. 2 straight from his original drawings, using only materials and tolerances available in his own time. It has roughly 8,000 parts, weighs about 5 tons, and when they cranked it... it worked. Flawlessly, to 31 digits. The man wasn't wrong. He was just born about 120 years too early.
Here is the leap, and it's the whole reason Babbage matters to us and not just to historians of math.
The Difference Engine, for all its tonnage, was a calculator. It did exactly one fixed job (finite differences) and nothing else, the same way your phone's calculator app can't suddenly decide to play music. But somewhere around 1833, while still tangled up in the unfinished Difference Engine, Babbage started dreaming of something categorically different: a machine that wasn't locked to a single task, but could be fed instructions and made to carry out any calculation you could describe. Not a calculator. A general-purpose, programmable computer. He called it the Analytical Engine.
And the way he designed it should make the hair on your neck stand up, because it's our machine, sketched in brass a century before its time. Look at the parts:
The punched-card heist (logic, stolen from a fabric loom). Where do you suppose Babbage got the idea to feed a machine instructions on punched cards? Not from anything to do with math. He stole it from weaving. Decades earlier, a Frenchman named Joseph Marie Jacquard had built a loom controlled by a chain of stiff cards with holes punched in them: a hole here lets a thread rise, no hole keeps it down, and that simple presence-or-absence of a hole, repeated across thousands of cards, lets the loom weave fantastically intricate patterns automatically, with no skilled human steering each thread. Stop and notice what that really is: a physical machine, following a stored program, made of holes and not-holes. Sound familiar? It's binary (Leibniz's 0 and 1 from the last section) wearing a workman's apron. Babbage was so taken with it that he owned a portrait of Jacquard woven on a Jacquard loom out of silk, using around 24,000 cards, and he'd show it off at parties. Punched cards went on to feed real computers all the way into the 1980s. A 200-year-old loom is the great-grandparent of the keyboard you're sitting at.
The big idea: Babbage made the jump nobody before him had managed: from a machine that does one fixed sum (a calculator) to a machine you can program to do anything (a computer), complete with a processor, a memory, instructions, decisions and loops. Nearly every concept sitting inside the laptop in front of you, he had on paper in the 1830s.
And now the part that makes Babbage one of the great tragic figures of our whole story.
The Analytical Engine was never built. Not a working fragment, not a demo, nothing. It was simply too vast, too far beyond what the workshops of the 1800s could machine, and too expensive for a government already burned once on the Difference Engine. Babbage kept refining it obsessively, drawing and redrawing thousands of pages, right up until he died in 1871. The most important computer of the 19th century existed only as ink on paper and a fire in one man's head. It would be over a hundred years before the world caught up and built its like.
But here's the strange and beautiful thing about a machine that exists only on paper: the only way anyone could ever "use" it was to imagine it. To run it in their mind. And the person who ran it furthest, who looked at Babbage's mountain of drawings and saw something blazing in there that even Babbage himself had not fully put into words, wasn't Babbage at all.
She was a young woman named Augusta Ada King, Countess of Lovelace. Daughter of the most scandalous poet in England. And she was about to write down something that, a full century early, would turn out to be the first true glimpse of what these machines really were, and the first algorithm ever written for one.
She was born Augusta Ada Byron in 1815, and yes, in case his name rings a bell, that Byron. Her father was Lord Byron, the most scandalous celebrity poet of the entire age, the original rockstar, a man one of his lovers famously branded "mad, bad, and dangerous to know." And he was barely in Ada's life for a single month. Her parents' marriage detonated almost immediately; Byron sailed out of England forever when she was about five weeks old, and died in Greece when she was eight. Ada never knew her father. Not once. She never met the most famous man in England, the man whose name she carried.
What she got instead was her mother, Lady Byron (Annabella), and here is where the story gets almost too poetic to be real. Annabella was herself sharp at mathematics (Byron had nicknamed her his "Princess of Parallelograms," which was not meant as a compliment, the man was a piece of work). And Annabella was terrified. Terrified that her daughter had inherited Byron's wildness, his recklessness, what she saw as a streak of poetic madness running in the blood. So she made a decision that would accidentally change the world: she would drill that poetry OUT of the girl. She had Ada schooled relentlessly, from earliest childhood, in mathematics and logic, specifically as an antidote. Cold, rigorous reason, deployed as a vaccine against her own father (that is some Warhammer-level bs right here; don't try that at home).
Sit with the irony for a second, because it's delicious: a mother tried to stamp the poet out of her daughter using mathematics, and instead raised the one person on Earth who would look at a machine made of brass and see poetry in it. Ada herself had a name for the way her mind worked, blending the two halves of her inheritance. She called it "poetical science" The father she never met and the mother who feared him, fused into one extraordinary way of seeing things.
Her teachers were not nobodies. Ada was mentored by Mary Somerville, one of the foremost scientists of the century (the word "scientist" was reportedly coined in part to describe her, since "man of science" obviously didn't fit). And later she was tutored in advanced mathematics by Augustus De Morgan, a brilliant logician. Hold onto that second name in particular, because De Morgan's laws are going to walk right back into your life in a few sections, when we get to logic and Boolean algebra. The threads in this story are absurdly interconnected.
In June 1833, at a London party, the seventeen-year-old Ada was introduced (through Mary Somerville's circle) to a prickly, frustrated mathematician you just met: Charles Babbage. He showed off the working fragment of his Difference Engine, that gleaming hunk of calculating brass.
Now, plenty of fashionable people saw that machine and went "oOoOoOoh, shiny," the way you'd stare at a fancy music box. Ada did something nobody else in that room did (because nobody was enough of a living legend to do it). She understood it. She grasped what it was actually doing, where it could go, what it really meant, and she did it at SEVENTEEN, faster and deeper than grown men (at this time women in scientific fields were few and far between sadly) who'd spent their lives in mathematics. Babbage, a man not easily impressed by other humans, was floored. What followed was years of intense friendship and mathematical correspondence: letters flying back and forth, Ada firing off questions and pushing back on his ideas, Babbage feeding her problems, the two of them turning his impossible dream over and over between them. He grew so fond of her, and so awed by her mind, that in a letter in 1843 he gave her the nickname that stuck to her forever: "The Enchantress of Numbers."
Here's where Ada earns her place at the very front of our story.
In 1842, an Italian engineer wrote up a description of Babbage's Analytical Engine (the big one, the real computer, the one that was never built) in a paper, in French. Ada was asked to translate it into English. And translate it she did, but then she kept going. She bolted on her own set of Notes at the end, labeled A through G, and those notes ran about THREE TIMES LONGER than the original paper she was supposedly just translating. They weren't footnotes. They were the main event. They were her, thinking harder about this machine than anyone alive, very much including Babbage himself (who, it was very visible, she was outshining in any meaningful way).
And buried in the last one, Note G, she laid out a complete, step-by-step procedure for getting the Analytical Engine to compute a sequence of fiendishly tricky values called the Bernoulli numbers.** A full algorithm** written out in detail for a machine that physically did not exist. This is why Ada Lovelace is celebrated as the first computer programmer (you'll catch pedants squabbling over the title, since Babbage scribbled his own bits of code too, but Note G is the most complete, most elaborated, published program of its era, and it was hers). She wrote software a century before there was hardware to run it on.
But honestly? Calling Ada "the first programmer" almost undersells her. Because she saw something even Babbage didn't.
The leap that nobody else made, not even the inventor. Babbage looked at his Analytical Engine and basically saw a magnificent number-cruncher, a machine for doing sums. Ada looked at the exact same machine and saw something vastly bigger. She realized that those numbers didn't have to BE numbers. If you could represent anything (letters, musical notes, ideas, relationships between things) as symbols the machine could shuffle around, then the machine could operate on all of it. She wrote, specifically, that if the rules of harmony and musical composition could be expressed in those terms, the engine might one day "compose elaborate and scientific pieces of music of any degree of complexity". In other words: In 1843, a woman looked at a pile of unbuilt brass gears and predicted that a computer could make music. That is not a programmer's insight. That is a genius's. She had grasped the single most important truth about the machine in front of you: a computer is not a calculator, it is a universal manipulator of SYMBOLS. It's not "doing math" when it shows you this text, or plays a song, or renders a game. It's shuffling symbols according to rules, exactly as Ada said it would. She saw the entire future of the thing, a hundred years early, while everyone else (Babbage included) was still seeing an adding machine.
She also, in those same notes, planted a careful warning: the machine, she said, "has no pretensions whatever to originate anything." It can only do what we know how to order it to do. Keep that thought somewhere safe, because almost exactly a century later a man named Alan Turing is going to take Ada's caution, name it after her, and argue with it head-on. (Yes, that Turing. He's coming. Everyone in this story eventually talks to everyone else.)
It would be easy to leave Ada there, gleaming, the visionary genius who saw the future. But she'd hate that, and so would I, because the whole point of this course is that these were people. And Ada's life was hard in ways that have nothing to do with brass.
Her body betrayed her early and often. As a child she suffered crippling headaches that disturbed her vision, and at around fourteen a bout of measles left her bedridden and partially paralyzed for the better part of a year; she was on crutches afterward. Ill health shadowed her for her entire, short life.
She married a man named William King in 1835; when he was made the Earl of Lovelace in 1838, Ada became the Countess of Lovelace, and that (in case you were wondering) is where the name we all know her by actually comes from. By the standards of the time it was a perfectly sensible aristocratic match, and her husband, to his credit, supported her unusual mathematical obsessions rather than crushing them. But it was a marriage of her era: arranged-feeling, expected, a respectable box for a brilliant and restless woman to be placed into. Later in life she developed a serious gambling habit, throwing herself into an attempt to build a mathematical system for betting on horse races (a very Ada thing to do, applying math to everything), and it went badly, landing her in real debt. Genius doesn't make you immune to being human, and she was gloriously human: brilliant, vain, obsessive, reckless, sometimes a mess. Like her father, a little. The poetry never did fully wash out.
And through all of it, her mother never let go. The same Annabella who had engineered her childhood was a controlling presence to the very end, and the end came far too soon. In 1852, Ada was diagnosed with uterine cancer, and she died from it that November, after months of terrible pain, with her mother managing her bedside and reportedly pressing the dying woman toward religious repentance. She was thirty-six years old. As always, the candle that burns twice as bright, also burns twice as fast...
She got 36 years. With them, she wrote the first program in history and saw a future nobody else could see. That is our hero.
Go read about her properly. I've barely scratched it. Here is a longer biography of Ada, and her actual Notes are online if you want to read the words of the first programmer in her own hand. If you got the time, do it. We owe her that.
After Ada and Babbage, the dream went quiet for a long time. The ideas were all there (a programmable machine, a mill, a store, instructions, decisions, loops, even Ada's vision of manipulating any symbol), but they were trapped on paper, because the world had no way to build them. Brass and gears and steam were simply too slow, too big, too clumsy to ever bring the Analytical Engine roaring to life.
What was missing was a way to make logic itself physical, and fast, and small. And, almost unbelievably, the seed of exactly that was being planted at nearly the same moment, by a self-taught Englishman who was busy doing something that sounds completely insane until it changes everything: turning the laws of human thought into algebra.
Ada's section ended with a promise: an Englishman, doing something that sounds completely unhinged until it reshapes the world, turning the laws of human thought into algebra. Time to meet him.
George Boole was born in 1815, the son of a shoemaker, in a family with no money for a fancy education (similar situation to Georg Ohm's, if you recall that from E1; well Boole was poorer still and with a lot less of a chance to make it into science). So he did what every other half-mad genius in this course seems to do: he taught himself (again, another figure about which we talked in E1 that taught himself math & science is Oliver Heaviside; hope you read the article about him that I included in the resource; If not you can find the E1 resource pack here . First he taught himself languages, then mathematics, largely alone, out of borrowed books. And this cobbler's son, with barely any formal schooling, ended up a professor of mathematics, and went on to invent an entire new branch of it.
You're going to notice this pattern so often it stops being a coincidence: Heaviside from E1, Ohm, Babbage, now Boole. The people who built this world were, almost to a one, told they couldn't, and did it anyway.
Some of them were also dirt poor, born too early for their invention to be made or born a woman in a time where science was artificially a men's field.
Think about this before you want to quit, would you?
Here is another insane thing Boole did. Back then, logic (reasoning, the study of what follows from what) was the turf of philosophers. It was done in words, argued in Latin, and had been more or less frozen since Aristotle. Mathematics was a totally separate kingdom, the land of numbers. Nobody thought the two had anything to do with each other. Boole looked at that wall and walked straight through it. His move: take a statement that can only be true or false (nothing in between, no "kinda-sorta-maybe") and treat it as a variable, where TRUE = 1 and FALSE = 0. Then he defined operations on these true/false variables: AND, OR, and NOT. And suddenly you could do algebra with truth itself. "Is it raining AND is it cold?" stops being a sentence and becomes an equation you can solve. Reasoning, reduced to calculation. (Sound familiar? It's Leibniz's "Calculemus!" from two sections ago, taking its first real step toward reality.)
Remember Augustus De Morgan, the logician who tutored Ada? He and Boole were friends and co-conspirators in this exact revolution, both dragging logic out of philosophy and into math at the same moment. De Morgan's laws are part of this Boolean world, and (told you the threads connect) you will personally use them in the back half of this course, the first time you write a complicated
ifcondition in C and need to flip it inside out.
Now bury this next part somewhere deep, like a time capsule you'll dig up later. Boole's entire system runs on just TWO values. True or false. 1 or 0. Does anything from E1 leap to mind when I say "a thing that is only ever in one of two states"? A switch. A switch is either open or closed. Hold. That. Thought. Because around eighty years after Boole, a young man at MIT is going to notice that Boole's true/false algebra and an ordinary electrical switch are literally the same thing, and that one observation becomes the bedrock of every digital computer alive. We'll get to him (his name is Shannon, and he's earned his own section). For now, just file it: logic became math.
Boole handed us the math for one way of computing: the discrete, two-state, counting way. The road Babbage's gears were already rolling down, and (spoiler) the road that eventually wins everything.
But for over a hundred years, a completely different way of computing wasn't merely competing with the counting road, it was flat-out winning. A way that doesn't count at all.
It measures.
This is one of the deepest ideas in this whole course, so slow down for it. There are two fundamentally different ways to represent a number in a machine:
And the analog road came with a genuinely gorgeous trick up its sleeve. If your numbers ARE physical quantities, then you can make physics itself do the arithmetic, for free.

The cleanest example sat in the pocket of every engineer on Earth for about three centuries: the slide rule. Here's the magic, and it's pure math. Multiplying big numbers by hand is a pain, but logarithms have a beautiful property: log(a × b) = log(a) + log(b). Multiplication becomes addition once you're in log-land. So: print two rulers with logarithmic scales, and slide one against the other. To multiply two numbers, you physically add their two lengths by sliding, and read the answer off directly. No gears. No electricity. No batteries. Just two sticks and the laws of logarithms, doing your multiplication for you. Every bridge, every engine, every rocket designed before about 1975 was computed on one of these.
Here you can see how one is used in practice if you're curious.
Fun fact: the most advanced machine humanity had ever built by then, the Apollo spacecraft, carried a human backup for its computer, and that backup was a stick. Astronaut Buzz Aldrin took a Pickett N600-ES slide rule to the Moon. When you've got a spaceship full of cutting-edge electronics and you still pack a sliding ruler just in case, that tells you how trusted, and how genuinely powerful, analog computing was.
Fun fact: the idea is ancient. Over two thousand years ago, the Greeks built the Antikythera mechanism: a hand-cranked box of intricate bronze gears that predicted the positions of the Sun, Moon and planets, and even forecast eclipses. It's the oldest known analog computer, and we only have it because it spent two millennia at the bottom of the sea in a shipwreck. People built computing machines before they built the Roman Empire.
A slide rule still needs a human to slide it. The true high-water mark of analog was machines that solved brutal problems continuously, in real time, all by themselves. And the most consequential of those lived where the stakes were highest: in war, in the cockpits of airplanes.
The problem. Picture dropping a bomb from a fast plane, miles up. The bomb does not just fall straight down. It keeps the plane's forward speed, so as it falls it also flies forward, for kilometers, while gravity and air resistance drag at it. To actually hit a target, you have to release the bomb a long way before you're overhead, at exactly the right instant, and that instant depends on your airspeed, your altitude, the wind, and the bomb's own ballistics. Now solve that, in your head, in a freezing vibrating aircraft, while people are shooting at you. Hopeless.
The solution: an analog computer in a box, the bombsight (the famous, fabulously expensive, top-secret Norden bombsight, and its naval fire-control cousins). And here is the part that should genuinely dazzle you, how a lump of gears does calculus. The building blocks:
Here is how one of those wonders of engineerings looked like:

Now wire all of that together. The bombardier dials in the live inputs (sets the airspeed, the altitude, cranks in the wind), and the whole assembly of shafts, gears, differentials and cams continuously grinds out the answer, when to drop, where to aim, updating smoothly the instant any input changes. No program. No clock. No steps. You nudge an input and the output just... follows, as fast as the metal can move. That is the soul of analog computing: it doesn't compute the answer in steps the way a digital machine does, it settles into the answer, because the machine is physically built out of the equations themselves.
A treat for the E1 crowd. The electronic version of this trick uses a component you already know in your bones: the capacitor. Remember I = C × (ΔV/Δt) from E1, the current into a cap depends on how fast its voltage is changing? Run that backwards: a capacitor's voltage is the running total (the integral) of all the current you've poured into it. So wire a capacitor and an amplifier together the right way and you have built a machine that performs calculus, in hardware, in real time. Electronic analog computers were built exactly like this, doing integration with the very same capacitors whose charging curves you sweated over a course ago. Calculus, done by a capacitor. Not a metaphor, a real thing people built and used.
If analog was this elegant, this fast, this powerful, why did it lose? Because it has rotten teeth under that pretty smile, and you should know every one of them:
Myth: "old analog computers were primitive junk." WRONG, and it's worth killing this one. For decades, analog computers were faster than any digital machine at the things they did, solving complicated differential equations instantly and in parallel, while early digital computers would have choked for hours. They aimed real guns, flew real planes, and ran the flight simulators that trained real pilots. They were not toys. They were the state of the art, and they did history-shaping work. They just had a ceiling.
And the real world found that ceiling fast. The Norden bombsight was famously sold as able to "drop a bomb into a pickle barrel from 20,000 feet." In actual combat, over cloud and flak, with a drifting mechanism and a terrified human feeding it imperfect numbers, accuracy was a tiny fraction of the legend, and most bombs missed by a wide margin. The most sophisticated analog computer of its age, defeated by the messy world it had to work in.
Here's the whole story in one breath. Analog was fast, often instant, and it did critical, world-changing work for over a century. But it was imprecise, drifty, single-purpose, and couldn't reliably store, copy, or reason. The future belonged to the other road, the one that COUNTS in discrete, perfectly-copyable, perfectly-exact steps. A digital 1 is a 1 whether it's hot or cold, whether you copied it once or a billion times, whether it's sitting in your hand or screaming across the planet down a fiber. That one property, exactness you don't lose, is what changed everything.
The big idea: there are two ways to compute. MEASURING (analog): make numbers into physical quantities and let physics do the math, fast and continuous, but imprecise, drifty, and locked to a single task. COUNTING (digital): make numbers into discrete states and shove them around by rules, exact, copyable, and general, which is exactly why it ate the world. Boole quietly handed us the algebra for the simplest discrete system there is, true and false, and you'll watch that algebra turn into electricity in a few sections.
But to actually build the digital future, the world was still missing two things. It needed a way to make Boole's logic physical, fast and dirt cheap (that's Shannon and the switch, soon). And, far more deeply, it needed somebody to answer a question nobody had ever properly asked: what does it even mean to "compute" something? When we say a procedure is "mechanical," what exactly do we mean by that? And is there anything that simply cannot be computed, no matter how clever your machine?
A strange, brilliant, doomed young Englishman was about to ask precisely that question. And to answer it, he would invent a computer made of nothing at all, a computer built out of pure thought.
His name was Alan Turing.
Alan Turing. One young man that would answer a question nobody had ever properly asked (which I absolutely low; there's a saying that true genius is attempting to ask questions nobody else is even close to seeing), accidentally invent the theoretical foundation of every computer that would ever exist, and prove (with a thought experiment and a logical trick) that there are things no machine can EVER (hope you like my ALLCAPS, althoug I've been using them ever since the last coure without you permission) do. All before the age of 24. And then go on to help win a world war. We'll get to that second part next time.
He also casually invented a voice encryption device
But first, the human being, because (as always in this course) that's the whole point.
Turing was, by every account, a bit of an odd duck. Brilliant in a way that made him hard to be around, painfully honest, often lonely, never quite fitting the mold England expected of a proper young gentleman. He was also, and I adore this detail, a genuinely world-class long-distance runner, good enough to be in the conversation for Britain's Olympic marathon team, who would sometimes just run the dozens of miles to a meeting rather than bother with the train. File that under "geniuses are weird".
And there's one story from his youth I can't leave out, because it seems to have aimed the rest of his life. At around sixteen, at boarding school, the awkward and isolated Turing met another boy: Christopher Morcom. Brilliant, warm, the first person who was ever truly Turing's intellectual equal, and (by every honest account) his first love. For a year or two they were inseparable, trading ideas about science and stars and mathematics late into the night. Then, in 1930, Christopher suddenly died, of tuberculosis caught from infected milk, at eighteen years old. Turing was shattered and he seems to never have recovered from it.
And here's why it matters to our story, not just to his heart. That loss is widely believed to have lit the question that burned in Turing for the rest of his life, that being could the mind be explained as nothing but physical matter? Is a person's thinking something that could, even in principle, live inside a machine? Where does the "you" actually reside, and could it be rebuilt? The most human grief imaginable pointed him straight at the most profound question in all of computing: is thought mechanical? He would spend his life chasing it. (If this man's story grabs you, and it should, the definitive biography is Andrew Hodges' Alan Turing: The Enigma. Read it properly someday; if you want to know how to get a hold of it easily, message me).
Around the turn of the 20th century, the German mathematician David Hilbert, possibly the most respected mathematician alive (and one of the best to ever do it), had a bold dream. He wanted to put ALL of mathematics on a perfect, unshakeable, mechanical foundation.
Three wishes:
Hilbert was so confident this would all work out that his motto, now on his tombstone, was "Wir müssen wissen, wir werden wissen": "We must know, we will know."
Then the universe said: lol, no.
As you will see, Turing demolished the last one but the first one was not upright for long either. A brilliant Austro-Hungarian logician, named Kurt Gödel bestowed us with his incompleteness theorem, shattering Hilbert's dream of Complete mathematics.
The linked article from Quanta Magazine is amazing but here is a much more digestable 5-minute video.
But the third wish, decidability, the Entscheidungsproblem, was still standing. Maybe there was at least a mechanical procedure to decide what's provable? In 1936, a 23-year-old Englishman set out to answer it. And to ask "is there a mechanical procedure," he realized he first had to pin down something nobody in history had ever bothered to define precisely: what is a mechanical procedure? What does it actually mean to compute something "mechanically," step by mindless step?
That question, "what is computation, really?", is the crowbar that pried the whole thing open.
Turing's answer was admirable in its simplicity. He basically said: let's imagine the simplest, dumbest, most stripped-down machine that could carry out any step-by-step procedure at all. If we are to throw away all abstractions, what is the absolute bare minimum? THe absolute baseline.
Picture this. (This is the famous Turing machine)

That's it. That is the entire machine. A tape, a head that reads/writes/shuffles left and right, a mood, and a rulebook. It looks insultingly simple. It looks like a toy a bored child would lose interest in.
Feed it a row of symbols and a clever enough rulebook, and step by patient step it'll add numbers, or copy them, or check whether there's an even count of them, ticking one square at a time like the world's most autistic metronome.
The most important thing Turing did was to prove that this ridiculous little tape-and-head contraption can compute literally anything that is computable at all. Any calculation, any algorithm, any procedure that a human, or any machine, or any future supercomputer could ever carry out by following definite rules, this dumb little machine can also do, given enough tape and enough time. It might be mind-numbingly slow and chew through a kilometer of tape to do it, but it can. Turing had captured the entire essence of "mechanical computation" in the simplest possible object.
And I want to be crystal clear, because this comes up from time to time:
Myth: "the Turing machine is some old computer they actually built." WRONG, and missing this misses the entire point. Nobody built one as a practical computer, and nobody ever wanted to. It has an infinite tape, you physically cannot build it. The Turing machine is a mathematical IDEA: a definition, a thought experiment, the single sharpest tool humanity has for reasoning about what computers can and cannot do. Its power is precisely that it lives in your head, not on a desk. (People do build adorable toy versions out of LEGO and the like, for teaching and fun. Cute. Still not the point.)
Now. Most Turing machines have their rulebook baked in: this one adds, that one copies, this other one checks for evenness. One machine, one job. (Sound familiar? It's the analog bombsight from the last section all over again, the equations carved permanently into the cams, one machine welded to one task forever.)
Which made a question arise in Turing's mind and this question might as well be the single most important thing in this course:
The rulebook is just a list of rules, right? Which is to say, it's just a bunch of symbols. And a Turing machine eats symbols on a tape. So... what if you wrote the rulebook of one machine out as symbols on the tape itself, and then built a special machine that reads that rulebook and does whatever it says?
He proved you can. There exists a Universal Turing Machine: a single, fixed machine that takes, on its tape, (1) a description of any other Turing machine you want, plus (2) that machine's input, and then faithfully simulates it. It reads the description of a machine, and becomes that machine.
You can go over the last paragraph again if it was a mouthful.
Because that "description on the tape" has a name you use every single day of your life. It's a PROGRAM. It's software. The universal machine is the hardware. Change the program on the tape, and the exact same machine does something completely different, without you rebuilding a single physical part.
This is why the laptop in front of you is not a calculator. It is a Universal Turing Machine made out of silicon. It does not have separate "web-browser circuitry" and separate "video-game circuitry" and separate "music-player circuitry" soldered inside it. It is ONE machine, reading different programs (different "descriptions on the tape") and becoming each one in turn. Open a browser, and the hardware is pretending to be a browsing machine. Close it, open a game, and the very same hardware is now pretending to be a game machine. One universal machine, infinite costumes. That, right there, is the deepest reason computers are so unreasonably powerful: you don't build a new machine for every job, you just write a new description.
Two ghosts in this room. Remember Ada, a full century earlier, staring at unbuilt brass and writing that the machine could manipulate any symbols, not just numbers, that it might one day compose music? She saw this. Turing proved it, and made it rigorous. And remember Babbage's dream of one general machine instead of a hundred specialized ones? The Universal Machine is the mathematical heart of why that dream even works. The threads of this course are not subtle, are they.
And file this one away with a big red bookmark, because we cash it in soon: in a few sections, when we get to how the modern computer got its shape (the "stored-program" idea, the thing everyone pins on a man named von Neumann), you're going to realize it is nothing more than Turing's Universal Machine dragged out of the realm of pure thought and built in actual hardware. The program living in memory, right next to the data, is the rulebook living on the tape, right next to the input. Same idea. Same Turing.
Turing wasn't done. And his second bombshell is darker, and in a way even more profound, than the first.
Remember, the whole point was to answer Hilbert's Entscheidungsproblem: is there a mechanical procedure to decide whether any given statement is provable? Turing reframed this as a question about his own machines, and the cleanest, most famous version is this, the Halting Problem:
Is there a general program that can examine any other program (plus its input) and correctly tell you whether that program will eventually FINISH (halt), or run FOREVER (loop endlessly)?
Seems like a perfectly reasonable thing to want, right? It would be wildly useful, imagine a tool that scans your code and goes "yep, this'll terminate" or "nope, infinite loop on line 12."
Turing proved, with cold finality: NO. No such program can possibly exist. Not "we're not clever enough yet." Not "we need a faster computer." It is mathematically impossible, forever. And the way he proved it is a piece of logical judo so gorgeous I have to walk you through it. (E1 people: this is our "let's actually count the joules in a single electron" moment. Roll your sleeves up.)
It's a proof by contradiction. We assume the magic program exists, then watch it destroy itself.
And there it is. There is no general procedure to decide whether programs halt, which means the answer to Hilbert's grand Entscheidungsproblem is a final, ringing NO. There is no mechanical procedure that can decide all of mathematics. Hilbert's third wish, killed stone dead by a 23-year-old armed with a thought experiment and a sentence that talks about itself.
Now feel the weight of this, because it's heavy. This is not a temporary limitation. It is not "computers were weak in 1936." There are problems that NO computer, no matter how godlike its power, running for a trillion years, can EVER solve in general. Computation came into the world with hard, permanent, mathematically-proven limits stamped into it from birth. The most powerful idea ever conceived arrived with its own "thou shalt not" carved right into the foundation. There is something genuinely humbling, and honestly a little eerie, about that.
This has real teeth, by the way. The Halting Problem isn't a museum curiosity. Its descendants mean you can never write a perfect program that detects all infinite loops, or one that catches all possible malware, or one that proves every other program bug-free, in general. Whole categories of "wouldn't it be nice if software could just check..." run headfirst into Turing's wall. The limit is real, and you'll bump into its children for the rest of your career.
A footnote that's really a co-headline. While Turing was doing all this in England, an American mathematician at Princeton named Alonzo Church was answering the exact same Entscheidungsproblem at the exact same time (1936), using a completely different and equally brilliant tool he had invented: the lambda calculus, a system that builds up all of computation out of nothing but functions taking functions taking functions. (If that sounds dizzyingly abstract, it is, gloriously so.)
Here's the astonishing part. Church's lambda calculus and Turing's machines, two systems that look nothing alike, turned out to be exactly equivalent in power. Anything you can compute with one, you can compute with the other, and vice versa. This led to what we now call the Church-Turing thesis: the bedrock idea that these systems capture everything that is computable, that the word "computable" simply means "doable by a Turing machine (or, equally, by the lambda calculus)." It's our very definition of computation, full stop.
Careful: it's called a "thesis," not a "theorem," and that's on purpose (very much in the spirit of "Ohm's law is not a law of the universe"). You cannot prove the Church-Turing thesis, because to prove it you'd first need a formal definition of "computable in the intuitive, anything-a-human-could-do-with-paper sense," and that's the very thing we don't have independently. So it's not a proven theorem, it's a deeply-supported claim about reality that has survived every test for ninety years. Everyone believes it. Nobody can prove it. File that distinction away; it matters.
Turing, suitably impressed (and impressing right back), sailed to Princeton to do his PhD under Church.
A debt repaid (Ada vs Alan). Remember Ada's careful warning, that the machine "has no pretensions whatever to originate anything," that it only ever does what we order it to? Years later, in 1950, Turing wrote a now-legendary paper asking flat-out whether machines could think, and he took Ada's warning on directly, by name, calling it "Lady Lovelace's Objection." And he wasn't at all sure she was right. That argument, can a machine ever truly originate, create, or think, opened by Ada in 1843 and reopened by Turing in 1950, is still raging today (and, ahem, happens to be rather topical at the moment, look around). Two of our heroes, a century apart, on opposite sides of the biggest question in the field. Nobody's won yet.
The big idea: Turing asked "what does it even mean to compute?", and to answer it he dreamed up the Turing machine: a tape, a head, a handful of states, the simplest possible thing that can carry out any step-by-step procedure. With it he proved two world-shaking things. One (the bright one): a single Universal Machine can run any program fed to it as data, which is the birth of software and the entire reason one computer can become anything, the seed of every device you will ever own. Two (the dark one, the Halting Problem): some things genuinely cannot be computed, by any machine, ever. He set out to answer an abstract puzzle about mathematics, and accidentally laid the theoretical foundation for the whole age you live in.
And now the story takes a cruel and extraordinary turn.
This gentle, eccentric, abstract young man, who had spent his twenties thinking about machines made of pure thought, infinite tapes and impossible halt-checkers and the lambda calculus, was about to be yanked clean out of the safe, quiet world of mathematics and hurled into the dirtiest, most concrete, highest-stakes problem imaginable. Because in September 1939, Britain went to war. And somewhere out across the Channel, the German military was firing off thousands of coded messages a day through a fiendish little machine that the finest cryptographers in Europe had pronounced utterly, mathematically UNBREAKABLE.
They were about to hand that problem to the one man on Earth who had just spent years teaching himself to think like a machine.
His name was on a list. And he was headed for a country house called Bletchley Park.
Way back in the Boole section I told you to bury a thought like a time capsule, and promised we'd dig it up. Grab a shovel.
Here's what was in the capsule. Boole's entire system runs on two values: TRUE and FALSE, 1 and 0. And an electrical switch (E1, remember) is only ever in two states: closed or open. Two ideas, identical in shape. For eighty years, nobody put them together.
Then in 1937, a 21-year-old master's student at MIT named Claude Shannon put them together, and the connection was so clean it more or less founded the digital age in a single document. His insight: Boolean logic isn't merely like an electrical circuit. It is one. Map it straight across:
That's the whole trick. Series and parallel, the exact two arrangements you sweated over in E1, ARE Boole's logical operators wearing copper. Which means you can build a physical machine, out of nothing but switches, that computes logic: feed in true/false as voltages, and the circuit hands back the answer Boole's algebra would have worked out on paper. Reasoning, done by electricity. Leibniz's "Calculemus!", four sections and 230 years later, finally plugged into a wall.
It gets called, with a completely straight face, the most important master's thesis of the century (the psychologist Howard Gardner, among others, has said as much). A 21-year-old's homework, and it's the foundation under every digital chip ever made.
Geniuses-are-weird, latest entry. Shannon was an absolute delight of a human: he juggled, rode a unicycle through the halls of Bell Labs, built a mechanical maze-solving mouse named Theseus (please take a look at the video, you can actually see and hear Claude talking), and constructed the famous "Ultimate Machine", a box whose one and only function is to reach out, switch itself off, and retract. A man who founded the information age and also built the world's most pointless gadget for fun. Respect.
And Shannon was nowhere near done warping the world. In 1948 he published the founding document of information theory, and gave us the fundamental unit we measure all data in: the bit, a single 0-or-1. Every "megabit" and "gigabyte" you have ever seen traces back to that paper. But the 1937 thesis is the one that matters to us right now, because it's the bridge we needed: the moment Boole's abstract logic became something you can solder.
The big idea: Shannon proved that Boolean logic and switching circuits are the same thing, so logic could finally be built out of physical parts. A switch is a Boolean variable made of metal. That single realization is the seed of every logic gate, and therefore every digital computer, that has ever existed.
One catch, though: a switch you flip by hand is hopelessly slow. To build a real computer you need a switch that another electrical signal can flip, millions of times a second, no human finger involved. That switch evolved fast: clunky relay -> hot, fragile vacuum tube -> and finally the transistor (Bell Labs, 1947, file that away, it comes roaring back later). Once you can build logic out of fast, automatic switches, you can at last build the thing Turing had only dreamed in pure thought. Which leaves one question: what shape should you build it in?
Red-bookmark time. Back in the Turing section I told you to file away the Universal Machine (the one that reads a program off its tape and becomes whatever that program describes), and promised we'd cash it in once we got around to building a real computer. Here's the payout.
By the mid-1940s the world finally had Shannon's switches in fast (vacuum-tube) form, and people built the first room-sized electronic computers. The most famous, ENIAC (1945, USA), was a beast: around 18,000 vacuum tubes, 30 tons of machine. And it had one genuinely miserable flaw.
To "reprogram" ENIAC, you didn't type a thing. You physically rewired it: cables, plugs, switches, all by hand. Setting it up for a new problem could eat a team's days. The hardware and the program were the same physical object, so changing the program meant rebuilding the machine. (Sound familiar? It's the analog bombsight all over again, and the one-job Turing machine: the task welded permanently into the hardware.)
The human computers, one last time. That brutal rewiring was done largely by six women, the ENIAC programmers (Jean Bartik, Betty Holberton and their colleagues), mathematics graduates who were among the very first programmers in history, and who got written out of the story for decades. Remember "computer" started as a job title for a human? These were some of the last of them, standing right at the doorway to the new world. Go learn their names.
Then came the leap that hands us every computer since. What if the program lived in memory, stored as plain numbers, sitting right alongside the data? Then "reprogramming" isn't rewiring at all. It's just loading different numbers into memory. The machine itself never changes; only the contents of its memory do.
Stop and stare at that. A program, stored as data, that the machine reads off and obeys. That is Turing's tape made real. The rulebook on the tape, sitting next to the input, is now the program in memory, sitting next to the data. The Universal Machine, dragged out of the realm of pure thought and cast in actual metal. This is THE idea that makes your laptop your laptop: you install software (load numbers into memory) instead of rebuilding the hardware every time you want it to do something new.
It's called the stored-program architecture, or, far more often, the von Neumann architecture, after a 1945 report by the staggeringly brilliant polymath John von Neumann.
Careful, the name does an injustice (very much in the "Ohm's law isn't really a law" spirit). That report, the First Draft of a Report on the EDVAC, circulated with only von Neumann's name on the front, so the whole idea got stamped with his name and kept it. But ENIAC's actual builders, Eckert and Mauchly, had much of it first, and Turing's own design work in the same direction is routinely underweighted too. The idea had a whole crowd of parents. One of them got the plaque. Most "named after one person" things in science are hiding a messier, more crowded truth like this.
There are two flavors of this, and you'll meet both (one of them in the very chips you'll program in this lab):
The chips in your hands. Most everyday desktop-style computers are essentially von Neumann. But the little microcontrollers you'll be programming in this bootcamp lean Harvard-style: the AVR chip inside a classic Arduino is the textbook example, splitting instruction and data paths for speed (real designs usually mix the two approaches, which engineers call "modified Harvard"). So you're not just reading about these architectures, you're about to hold one and tell it what to do.
The big idea: store the program in memory as data, and the machine becomes universal: you change the software, not the hardware. That is Turing's Universal Machine rebuilt in silicon, and it's why one computer can be a thousand different machines. von Neumann = one shared memory and bus (flexible, but bottlenecked); Harvard = separate ones (faster, stricter). Between them, that's the shape of very nearly every computer ever built.
So far we've sized up the machine from the outside: its overall shape. Time to crack the lid and start naming the parts inside: the CPU, the ALU that does the actual arithmetic (Babbage's "mill", remember him calling it that?), the registers, the memory, and the buses they all shout across. Let's open the box.
Enough circling the machine from outside. Pop the lid. Strip away the marketing and a computer is basically three things plus the roads connecting them.
1. The CPU (Central Processing Unit), the "brain." The chip that actually does stuff: reads instructions and carries them out, one after another. Crack it open and the parts that matter to us right now are:
2. Memory (RAM), the "workspace." A big array of slots holding both the program and its data while the machine runs (yes, both, that's the stored-program idea from last section, sitting right here in front of you). It's far roomier than the registers but also far slower to reach. And here's the only thing about memory you need today:
Memory is just numbered mailboxes. Picture a huge wall of identical little boxes, each holding a number, and each with an address, which is itself just a number: box 0, box 1, box 2, and on and on. That's it. When the CPU wants something, it doesn't grope around, it says "give me what's in box 4,710," and memory hands it over. The crucial idea to swallow: an address is just a number that tells you WHERE, and the contents are just a number that tells you WHAT. (What's physically inside a box, how a "number" is even stored in there, and how RAM is actually built, we're deliberately saving all of that for the next course. Today: numbered boxes. Move on.)
3. The buses, the "roads." The CPU and memory are separate things, so you need wires between them to shuffle information back and forth. A bunch of wires carrying data as a group is a bus. Roughly: the address bus carries which mailbox the CPU wants, the data bus carries the actual number going to or from it, and a control bus carries the "am I reading or writing?" signals. (Remember von Neumann vs Harvard from last section? This is exactly what differed: one shared road for everything, or separate roads for instructions and data.)
The big idea: a computer is a CPU (which thinks, using its ALU to crunch and its registers as instant-access scratch space), a memory that holds the program and data as numbers in addressed mailboxes, and the buses wiring them together. That's the skeleton. Everything else is detail.
We've got the parts. But what makes them actually go? Two things: a relentless beat, and a relentless little ritual it drives.
The clock. Somewhere on the board, a crystal ticks, millions or billions of times a second, and that tick is the computer's heartbeat. Every tick, the machine takes one more tiny step in lockstep. This is what a chip's speed in GHz actually means: gigahertz = billions of ticks per second. A 3 GHz CPU's heart beats three billion times a second. Nothing in the machine moves between ticks; the clock is the drummer everything marches to.
A faster clock means more steps per second, sure. But this is also exactly why CPUs run hot and why people obsess over cooling: every one of those billions of switch-flips per second dumps a little heat (E1 again, current through resistance makes warmth). Crank the beat higher and you make more heat. There's no free lunch.
Fetch -> decode -> execute. What does the CPU actually do on those ticks? It runs the same three-step loop, over and over, forever, from the instant you power on until you shut down. Just three moves:
That's the whole life of a CPU. Fetch, decode, execute. Billions of times a second. Every program you have ever run, every game, every video, every line of code you're about to write, is nothing but this dumb little loop, repeated mindlessly at blinding speed. There is no magic in there. There's a drumbeat, and a three-step shuffle.
The big idea: the clock ticks billions of times a second and paces everything. On those ticks the CPU runs one eternal loop, fetch -> decode -> execute: grab the next instruction, figure out what it means, do it, repeat. A computer's entire behavior, all of it, is that loop going stupidly fast.
Reading about fetch-decode-execute is one thing. Watching a number physically leave memory, ride the bus into the CPU, and get processed, that's when it clicks. So let's do exactly that, with a beautiful little teaching tool called the Little Man Computer (LMC).
The story it's built on: imagine a "little man" locked inside a mailroom. The room has 100 numbered mailboxes (there's your addressed memory, the mailboxes made literal), a calculator he does sums on (the ALU + accumulator), a little counter telling him which box to read next (the program counter), and an in-tray and out-tray for talking to the outside world. To run a program, the little man just does fetch-decode-execute by hand: walk to the box the counter points at (fetch), read the instruction and understand it (decode), do what it says on his calculator (execute), tick the counter up, repeat. It is a real computer, slowed down to human speed so you can see every move.
You write it tiny programs in a simple assembly language, just a handful of instructions like LDA (LoaD the Accumulator from a mailbox), ADD (add a mailbox's value to the accumulator), STA (STore the accumulator into a mailbox), OUT (send it to the out-tray), and HLT (halt).
Go play. This is not optional reading, it's the point. Open an LMC simulator (there are several free ones in the browser; the polished one by Peter Higginson is the usual go-to and is linked on the resources page). Type in a small program, one that reads two numbers and adds them is the classic first, and then run it one step at a time. Watch it with your own eyes:
- the counter points at a mailbox -> the little man fetches that instruction (FETCH);
- he reads what it means (DECODE);
- a value leaves a mailbox, crosses into the accumulator, gets added (EXECUTE);
- the counter ticks up, and the whole thing repeats.
That right there, a number leaving RAM, crossing into the CPU's accumulator, the cycle stepping forward, is everything from the last two sections happening in front of you, in slow motion. Every concept (mailboxes, buses, accumulator, fetch-decode-execute) made visible. Single-step a program until that loop is burned into your brain. Do it before you read on.
And here's the thing to sit with once you have. That wheezing little man, shuffling between a hundred mailboxes and a calculator, is doing the exact same job as the 3-billion-ticks-a-second monster in your laptop. Same loop. Same parts. The only difference is speed and scale. You now understand, genuinely understand, what the machine in front of you is doing. We just have to make the little man go a few billion times faster.
So we've got the machine: its shape, its parts, its heartbeat, its loop. The obvious next question is the one that runs the rest of this course: how on earth do humans tell this thing what to do without hand-writing mailbox-shuffling instructions all day? The answer is a tower of clever lies we tell the machine (and ourselves), and it's called abstraction.
You just watched the Little Man Computer shuffle numbers between mailboxes. Now imagine writing a video game like that. By hand. In mailbox-shuffling instructions. Millions of them.
You'd quit. Everyone would quit. Nobody could build anything bigger than a toy if they had to think about individual mailboxes and clock ticks the whole time. So we don't. Instead, we built a tower, where each floor hides the messy details of the floor below it and offers something simpler to stand on. That hiding has a name, the most important word in all of software: abstraction.
Here's the whole tower, bottom to top:
LDA, ADD, STA... sound familiar?). Stop thinking about gates, start thinking about instructions.Each layer trusts the one beneath it and ignores how it works. When you write C, you do not care which transistors flip, the same way you drive a car without thinking about combustion. That's abstraction: a deliberate, useful blindness that lets you build big things without drowning in small ones.
The big idea: abstraction is hiding complexity behind something simpler, stacked in layers from electrons at the bottom to your ideas at the top. Each floor lets you forget the one below. It's the only reason a human can build something as monstrously complicated as modern software, you only ever stand on one floor at a time. And you, lucky thing, get to stand near the top.
So you'll write C, a comfy high-level floor near the top of the tower. But the CPU you met doesn't understand C. It understands one thing: numbers in mailboxes, raw instructions. So something has to carry your readable C all the way down the tower and turn it into those numbers. That something is a small assembly line called the toolchain, and watching it work is genuinely one of the most clarifying things in this whole course.
It runs in four stages. Say your file is hello.c:
1. Preprocessing. A quick "find and replace" pass that runs before real compilation. It handles the lines starting with # (you'll write #include <stdio.h> in about five minutes): it pastes in other files, swaps out shortcuts, strips comments. Think of it as tidying and assembling the full text of your program before the serious work starts.
2. Compiling. The heart of it. The compiler takes your preprocessed C and translates it into assembly, that human-readable-but-very-low-level layer from the tower (the one that's basically the CPU's own instructions with names). This is the big leap, high-level idea -> low-level instructions, and it's where decades of brilliant engineering live: the compiler doesn't just translate, it optimizes, often finding cleverer instruction sequences than you'd write by hand.
3. Assembling. Now the assembler takes that assembly and converts it the rest of the way down into machine code, the actual raw numbers the CPU executes (the real contents of those mailboxes). This step is nearly mechanical, assembly was designed to map almost one-to-one onto machine code. The result is an object file (hello.o): real machine code, but not yet a runnable program.
4. Linking. The last stitch. Your program almost always leans on code somebody else already wrote, when you call printf to print to the screen, you didn't write printf, it lives in the standard library. The linker takes your object file and bolts on all that external code it needs, producing one complete, runnable executable at last. This is the file that runs.
So the full journey: hello.c -> [preprocess] -> [compile] -> [assemble] -> [link] -> a running program. Your readable text walks down the entire tower of abstraction, floor by floor, until it's nothing but numbers a CPU can fetch-decode-execute.
Go SEE the big leap happen, live. The single best way to feel "high-level becomes machine code" is a free in-browser tool called Compiler Explorer (a.k.a. godbolt, linked on the resources page). It's dead simple and a little magical: you type C on the left, and the assembly it compiles to appears instantly on the right. Better yet, hover over a line of your C and it highlights the exact assembly instructions that line turned into. Write a one-line function that adds two numbers, watch a few assembly instructions light up. Change something, watch the right side change. This is the compiler step from above, made visible, and it makes the whole tower suddenly feel real. Play with it.
Wait, do I do all four steps by hand every time? Nope, thank goodness. In practice one command quietly runs the whole pipeline for you, you'll type something like
gcc hello.c, and preprocess-compile-assemble-link all happen in one go, handing you a finished program. You can ask to stop after any single stage (handy when you're curious, or hunting a bug), but day to day it's one command and done. The assembly line is there; it just usually runs without you watching.
The big idea: the toolchain walks your C down the tower in four steps, preprocess (tidy the text), compile (C -> assembly, the big leap), assemble (assembly -> machine code), and link (bolt on the library code you used) -> leaving a runnable program of pure numbers. One command usually runs the lot, but now you know what's happening under it. And with Compiler Explorer you can watch the key step with your own eyes.
If you read the "Why C?" side-read, you already know why we're starting you specifically on C and not something flashier. If you didn't, no harm: all you need to know is that C sits close to the machine you just spent an entire course dissecting, close to the mailboxes and the registers and the fetch-decode-execute loop. Writing C, you're standing on a fairly low floor of that abstraction tower, close enough to feel the hardware underneath. That's exactly why it's the right first language for people who just learned how the box actually works.
So let's write the most famous program in the world. Tradition is absolute here: your very first program in any language prints the words "hello, world" and nothing else. And this isn't a random ritual, it comes straight out of the book at the heart of the side-read: K&R, The C Programming Language by Kernighan and Ritchie. The little greeting was made famous in those exact pages, by the exact people who made C. Every "hello, world" ever typed, in every language since, is a quiet nod back to them. You're joining a fifty-year-old tradition.
Here it is:
#include <stdio.h>
int main(void) {
printf("hello, world\n");
return 0;
}
Five lines. Let's read every single one, because there is zero magic here and I want you to see that:
#include <stdio.h> -> remember the build pipeline, the lines starting with # that the preprocessor handles before real compilation? This is one. It pastes in the declarations for the standard input/output library, which is where printf lives. Without this line, the machine has never heard of printf. You're telling it "go grab the toolbox that has the printing tool in it."int main(void) -> every C program starts running at a place called main. The operating system loads your program and goes straight to main, no matter where it sits in the file. (It's a function, the thing we build properly in a couple of sections. For now: it's the front door.) The int means it hands back an integer when it's done, and the (void) means it takes no inputs.{ and } -> curly braces wrap up the body of main, everything the program actually does. In C, braces always mean "here is a block of stuff that belongs together." You'll see them everywhere.printf("hello, world\n"); -> the one line that does real work. It calls printf and hands it some text to print. That \n on the end is an escape sequence meaning "newline", press Enter, move to the next line. (Without it, the next thing printed would jam right up against your text.) And notice the semicolon: in C, almost every statement ends in a ;. It's how you tell the machine "this instruction is finished." Forget one and the compiler will yell at you, get used to it now.return 0; -> main hands the number 0 back to the operating system, and by convention 0 means "everything went fine." A non-zero number means "something went wrong." This is how programs report success or failure to whatever launched them. (You'll feel why this matters the first time you chain programs together, very Unix, very side-read.)That's the entire thing. Now the loop you're going to live inside for the rest of your coding life:
The compile-run loop. Programming in a compiled language is a rhythm: write some code -> compile it (run it down the toolchain into a runnable program) -> run it and see what happens -> edit -> compile -> run -> edit... round and round. Most of programming is not typing; it's this loop. You write a bit, you run it, it does something wrong or stupid, you fix it, you run it again. Get comfortable spinning this loop fast and cheap, because you'll do it ten thousand times.
Go run it, two ways, right now. You don't need to install anything to start.
- First, OnlineGDB (a free in-browser C compiler-and-runner, linked on the resources page). Paste the program in, hit Run, and watch
hello, worldappear in the output. You just made a machine speak. That output wentyour C -> the whole toolchain -> machine code -> the CPU's fetch-decode-execute loop -> text on your screen. Everything from the last several sections, fired in one click.- Then, Python Tutor (yes, it runs C too, also linked). Paste the same program and step through it one line at a time. Watch the little arrow walk down your code, hit the
printf, and produce the output. Seeing execution crawl line by line, at human speed, is the single fastest way to stop thinking of code as spooky incantations and start seeing it as a list of steps the machine does in order. Use it constantly this lesson.Until you've made your own
hello, worldactually run, don't read on. This is the "go light the LED" moment of CS1.
Got text on a screen? Congratulations, genuinely. You've closed the entire loop, from a human idea to a CPU obeying you. Everything from here is just learning to say more interesting things than "hello, world."
hello, world is a program that can't remember anything. To do anything interesting, a program needs to hold on to values: a score, a name, a temperature, an age. For that, you need variables.
And here's the beautiful part, because you already know exactly what a variable is. Cast your mind back to the section on memory: it's a giant wall of numbered mailboxes, each holding a number, each with an address. A variable is just a mailbox you've given a human-friendly name, so that instead of saying "the value in box 4,710," you can say "age." The name is a convenience for you; underneath, it's still a box in memory at some address. That's the whole idea. You're reserving a box and slapping a label on it.
Here's how you make some:
int age = 16;
char grade = 'A';
float price = 3.99f;
double pi = 3.14159265358979;
Each line declares a variable: it picks a type, gives it a name, and (here) sets a starting value. Read int age = 16; as "reserve a mailbox called age that holds whole numbers, and put 16 in it."
But what's with that first word on each line, int, char, float, double? That's the type, and C cares about it intensely. Here's why, and it ties straight back to the hardware: a mailbox has to be a particular size, and the bits inside it have to be interpreted the right way. C is a low-floor, close-to-the-metal language, so you tell it both. The type answers "how big is this box, and how do I read the bits in it?"
The four you need right now:
int -> a whole number (an integer): -3, 0, 42, 1000000. No fractional part. On the computers you're using it's usually 4 bytes (32 bits), which holds values up to about ±2 billion.char -> a single character: a letter, a digit, a symbol. You write the value in single quotes: 'A', 'z', '?'. It's just 1 byte. And here's a secret that's going to matter at the very end of this course: a char is secretly a small integer. The character 'A' is really just stored as the number 65 (its code in a scheme called ASCII). The machine doesn't store letters; it stores numbers and agrees that 65 means 'A'. (Ada told you this in 1843, remember? A computer manipulates symbols, and underneath, the symbols are numbers.)float -> a number with a fractional part: 3.14, -0.5, 99.99. "Float" is short for floating-point, the clever scheme computers use to store decimals. It's 4 bytes and good for about 7 significant digits. (That little f on 3.99f just tells C "I mean a float here.")double -> the same idea as float, but with double the precision: 8 bytes, good for about 15 to 16 digits. When in doubt and you need decimals, reach for double; it's the default workhorse for fractional numbers.How do you prove types are about size? C hands you an operator that tells you, in bytes, how big any type is: sizeof.
printf("an int is %zu bytes\n", sizeof(int));
printf("a char is %zu bytes\n", sizeof(char));
printf("a double is %zu bytes\n", sizeof(double));
(Don't worry about the %zu placeholder yet, it's a printing detail we unpack in the very next section. Just know each line prints a number.) Run that and you'll typically see 4, 1, and 8. Concrete proof that an int really does eat four mailboxes' worth of space while a char sips just one.
Honesty note, and this one's for the embedded crowd especially. I keep saying "usually 4 bytes" instead of "4 bytes", and that hedge is deliberate. The C standard does not nail down most of these sizes! It only guarantees minimums and relationships (a
charis exactly 1 by definition, anintis at least 2 bytes, adoubleis at least as big as afloat, and so on). On the desktop you're learning on,intis 4 bytes. But drop down onto a small microcontroller (exactly the little chips you'll program later in this bootcamp) and anintmight well be 2 bytes, and your "±2 billion" assumption silently becomes "±32 thousand", and your code breaks in a baffling way. This is the C version of E1's "Ohm's law isn't really a law": the simple story is true most of the time, on most hardware, and a real engineer knows where the fine print bites.sizeofexists precisely so you never have to guess.
Go watch variables be born. Back to Python Tutor. Write a few lines that declare and change some variables, then step through them. As each line runs, watch the variables literally pop into existence in the memory panel and change their values. That's the mailbox model, made visible: each variable is a labeled box, appearing and updating as the program walks line by line. Seeing it once makes "a variable is a named box in memory" click permanently.
(And the address of the box itself? You can get at it, and a whole world opens up when you do, it's called a pointer. But that's a future-you problem, deferred to the next course. Today, a variable is a named box, and that's plenty.)
A program that can't talk to you is a closed loop. Let's open it: output (the program tells you something) and input (you tell it something).
You've already used printf, "print formatted." You've been printing fixed text. Now the real power: format specifiers, little placeholders inside the text string that get filled in by your variables at runtime.
int age = 16;
printf("I am %d years old.\n", age);
That %d is a placeholder meaning "an integer goes here." When printf runs, it reads along the text, and every time it hits a % specifier, it grabs the next value you handed it (here, age) and slots it in. Output: I am 16 years old.
The specifiers you'll use constantly, matched to the types from last section:
%d -> an int (a decimal integer)%f -> a float or double (a number with a fractional part)%c -> a single character (char)%s -> a string (a piece of text; we'll meet strings properly later)%zu -> the special type that sizeof hands back (that's where last section's mystery came from)You can slot in several at once, and they fill left to right:
char grade = 'A';
int age = 16;
printf("Age %d, grade %c.\n", age, grade);
Output: Age 16, grade A. First placeholder takes age, second takes grade, in order. Mix up the order, or use %d where a %c belongs, and you'll get nonsense, the placeholders and the values have to line up.
Now the reverse. scanf ("scan formatted") reads input typed at the keyboard and stuffs it into a variable.
int age;
scanf("%d", &age);
This says "read an integer the user types, and store it in age." Same specifiers as printf (%d for an int, and so on). But look very closely at that &age, because it trips up every single beginner, and the reason it exists is a thing of beauty.
Why the
&? It's the mailboxes again. Whenprintfreads a variable, it only needs the value inside the box, so you just hand itage. Butscanfhas to write a new value into a box, which means it needs to know which box to write into, it needs the box's address. And&means exactly that: "the address of."&ageis "the address of theagemailbox." You're handingscanfthe location to deliver the answer to, like giving a courier the house number. So the rule, until you learn pointers properly:scanfneeds an&before the variable,printfdoes not. It's not arbitrary;printfreads contents,scanfwrites to an address. (And yes, that&is your first tiny peek at pointers. Wave at it. We'll properly meet them next course.)
Now let's put output and input together in a real program, and notice what it is:
#include <stdio.h>
int main(void) {
int a, b;
printf("Enter two numbers: ");
scanf("%d %d", &a, &b);
printf("Their sum is %d\n", a + b);
return 0;
}
Look familiar? It should. This is the exact same program the Little Man Computer ran, "read two numbers, add them, output the result", except now you're writing it in C instead of hand-feeding mailbox instructions to a little man. Same job. Higher floor of the tower. That's what abstraction bought you.
You can store values and shuffle them in and out. Now let's operate on them. Operators are the symbols that combine and compare values, and they come in three families you need today.
int sum = a + b; // addition
int diff = a - b; // subtraction
int prod = a * b; // multiplication
int quot = a / b; // division
int rem = a % b; // modulo (the REMAINDER)
The first four are no surprise. % (modulo) might be new: it gives the remainder after division. 7 % 3 is 1 (7 divided by 3 is 2 remainder 1). It's secretly one of the most useful operators you have, the classic trick n % 2 == 0 checks whether a number is even (remainder 0), which you'll use constantly.
But here is a trap that will bite you, hard, and confuse you for an hour the first time:
Integer division throws away the fraction. In C, when you divide two integers, the result is also an integer, the fractional part is just chopped off, not rounded. So
7 / 2is3, NOT 3.5. The.5vanishes. This is not a bug, it's the rule: int divided by int gives an int. If you actually want3.5, at least one of the numbers has to be a floating-point type:7.0 / 2gives3.5. Forget this and your "average" function will quietly return wrong answers and you'll have no idea why. Burn it in: int / int = int, fraction discarded.
These ask a yes/no question about two values and hand back an answer: 1 for true, 0 for false.
a == b // are they EQUAL? (note: TWO equals signs)
a != b // are they NOT equal?
a < b // is a less than b?
a > b // greater than?
a <= b // less than or equal?
a >= b // greater than or equal?
And right here is the single most infamous beginner bug in all of C:
==is NOT=. A single=means assignment ("put this value into this box"):age = 16stores 16. A double==means comparison ("are these equal?"):age == 16asks a question. Mix them up, writeif (age = 16)when you meantif (age == 16), and you don't get an error; you get a program that silently misbehaves, because you accidentally set age to 16 instead of checking it. This bug has eaten more beginner hours than any other. One equals stores. Two equals asks. Say it in your sleep.
And now, an old friend returns. These three combine true/false values:
a && b // AND (true only if BOTH are true)
a || b // OR (true if EITHER is true)
!a // NOT (flips true to false and back)
You have met these before. By name. In a different century.
&&,||,!, these are AND, OR, and NOT: George Boole's three operators, the algebra of true and false that a self-taught cobbler's son invented back in the history section. When you writeif (age >= 13 && age <= 19)to check "is this person a teenager," you are doing Boolean algebra, the exact thing Boole formalized and Shannon turned into circuits. It went: Boole's logic -> Shannon's switches -> logic gates -> your CPU's ALU -> and now back up to a line of C you type. The whole tower, round trip. And remember De Morgan, the logician who tutored Ada? I promised his laws would come back:!(a && b)is exactly the same as(!a || !b). That's De Morgan's law, and you'll reach for it the first time you need to flip a complicated condition inside out. The threads of this course really, truly connect.
(One small C quirk worth a line: classic C has no dedicated "boolean" type. It uses integers, where 0 is false and anything non-zero is true. A comparison like a < b hands back exactly 1 or 0. So true and false in C are really just numbers in disguise, fitting, given everything you now know.)
Every program so far has run top to bottom, every line, exactly once. That's it. That's a glorified calculator. Real programs do two things that boring straight-line code can't: they make decisions (do this or that, depending), and they repeat (do this over and over). Bending that straight march is called control flow, and it is where programming actually comes alive.
You watched this get invented. Remember Babbage and Ada's Analytical Engine, back in 1837? I told you the two ideas that lifted it from "fancy adding machine" to "genuine computer" were conditional branching (making a decision) and loops (repetition), and that they were the beating heart of every program you'd ever write. This is that section. And at the machine level, remember the program counter, the CPU's "finger" pointing at the next instruction, normally just ticking up by one? Control flow is what lets that finger jump: skip ahead, or leap back to repeat. You're about to use, in C, the exact two ideas a countess wrote down for a machine made of brass that was never even built.
if (age >= 18) {
printf("You can vote.\n");
} else {
printf("Not yet.\n");
}
Read it plainly: the bit in parentheses is a condition (a true/false Boolean expression, Boole again). If it's true, run the first block. Otherwise (else), run the second. The else is optional, sometimes you only want to act when something's true and do nothing otherwise.
For more than two paths, chain them with else if:
if (score >= 90) {
printf("A\n");
} else if (score >= 80) {
printf("B\n");
} else if (score >= 70) {
printf("C\n");
} else {
printf("Keep going\n");
}
It checks each condition top to bottom and takes the first one that's true.
int i = 0;
while (i < 5) {
printf("%d\n", i);
i = i + 1;
}
A while loop checks a condition, and as long as it's true, runs its block, then checks again, and again, and again. Trace this one: i starts at 0, condition 0 < 5 is true so it prints 0 and bumps i to 1, then 1 < 5 is true so it prints 1... until i is 5, 5 < 5 is false, and the loop stops. Output: 0, 1, 2, 3, 4.
(That i = i + 1 is so common that C gives you a shortcut: i++, which means exactly "add 1 to i." You'll see it everywhere. Fun aside: the language C++ is literally named after this operator, it's a cheeky in-joke meaning "C, incremented", "C, but one better." A pun, hiding inside one of the most famous names in software.)
The infinite loop, and a ghost from the history. What happens if you forget to change the variable the condition depends on? If you drop that
i++? Thenistays 0 forever,0 < 5is always true, and your program loops forever, printing 0 endlessly until you kill it. You will do this by accident. Everyone does. But here's the eerie part: remember Turing and the Halting Problem? You just wrote, by hand, exactly the kind of program-that-runs-forever that Turing proved no program can reliably detect in general. There is no perfect tool that will scan your code and warn you about every infinite loop, Turing settled that in 1936. So this one's on you to catch. The theory you learned isn't abstract trivia; it's the reason your compiler can't save you here.
When you're counting (which is most of the time), there's a tidier way to write that exact while loop. The for loop bundles the three pieces, where you start, how long to keep going, and how to step, onto one line:
for (int i = 0; i < 5; i++) {
printf("%d\n", i);
}
Three parts inside the parentheses, separated by semicolons:
int i = 0 -> the start (run once, at the beginning).i < 5 -> the condition (checked before every pass; keep going while true).i++ -> the step (run after every pass).This for loop does the identical thing as the while loop above, 0 through 4, just with the three counting pieces gathered tidily in one place instead of scattered. Reach for for when you're counting a known number of times; reach for while when you're looping until some condition you can't count out in advance.
When you're checking one variable against many specific fixed values, a long else if chain gets ugly. switch is cleaner:
switch (grade) {
case 'A':
printf("Excellent\n");
break;
case 'B':
printf("Good\n");
break;
default:
printf("Keep going\n");
break;
}
It looks at grade, jumps to the matching case, and runs it. default catches anything that matched no case (like else).
The
breakis not optional, and here's the trap. Eachcaseneeds abreak;at the end. Leave it off, and C "falls through", it keeps running straight into the next case's code too, even though that case didn't match. (It's occasionally useful on purpose, but 99% of the time a missingbreakis just a bug.) So: onebreakpercase, every time, unless you really know why you're skipping it.
Go step through a loop, slowly. Last call for Python Tutor this lesson, and maybe the most valuable. Write the
forloop above, and single-step it. Watchistart at 0, watch the condition get checked, watch the body run, watchitick up, watch it loop back... and watch the exact moment the condition turns false and the loop exits. Loops are the first thing that feels genuinely confusing on paper and suddenly obvious once you watch the counter crawl with your own eyes. Do it until the rhythm (check -> run -> step -> check) is automatic.
Here's a secret: you've been using functions since hello, world. main is a function. printf is a function. A function is just a named, reusable chunk of code that does one job, you hand it some inputs, it does its work, and it (optionally) hands back a result. Now you build your own.
int add(int a, int b) {
return a + b;
}
Let's dissect it piece by piece, the way we dissect everything:
int (the return type) -> what kind of value this function hands back when it's done. This one returns an int.add (the name) -> what you'll call it by.(int a, int b) (the parameters) -> the inputs it expects, each with a type and a name. Think of a and b as little local mailboxes that get filled with whatever values you pass in when you call it.{ ... } (the body) -> the actual work.return a + b; -> compute the sum and hand it back to whoever called the function, then exit. return is how a function gives you its answer.And you call it like this:
int result = add(3, 4); // result is now 7
printf("%d\n", result); // prints 7
You passed 3 and 4 in (they became a and b inside), the function computed 3 + 4, returned 7, and that came back out into result. Clean.
What if a function does something but has no answer to hand back, like one that just prints? Then its return type is void (meaning "nothing"):
void greet(void) {
printf("Hello there!\n");
}
The same word, two jobs (E1 people will smile). Notice
voidshows up in two spots and means related but distinct things. As a return type (void greet(...)), it means "hands nothing back." Inside the parentheses (...(void)), it means "takes no inputs." Same keyword, two positions, two meanings, exactly the kind of notation collision I flagged in E1 (theC-for-capacitance vsC-for-coulombs clash, thee-for-Euler vse-for-electron-charge clash). Context tells you which. Welcome to the eternal letter shortage in technical fields.
So why bother with functions at all? Two big reasons:
This is the Unix philosophy, and now you're living it. Remember the heart of the side-read, Thompson and Ritchie's whole worldview baked into Unix and C? Small, sharp tools that each do one thing well, combined to do big things. A good function is exactly that, at the scale of your own program: small, focused, one clear job, a clean name. When you break a problem into well-named functions that each do one thing well, you are not just "writing code", you're thinking the way the people who built the foundation under your feet thought. That is the difference between someone who types code and an engineer. Write small tools. Name them honestly. Make each do one thing well. The whole craft is in there.
(One practical note so the compiler doesn't bite you: in C, a function has to be known before it's used. Easiest rule for now, define your own functions above main, so they're already known by the time main calls them. There's a tidier way involving "prototypes" for bigger programs, but above-main is all you need today.)
Stop and look back at the road you just walked.
You started CS1 with a magic box you couldn't explain. We went all the way to the bottom, to math and al-Khwarizmi, to brass gears and a countess who saw the future, to a machine made of pure thought and a war won partly with logic, to a switch that became a circuit, to the shape of the modern machine and the relentless little loop at its heart. Then you cracked the lid, named every part, watched a little man shuffle mailboxes, and climbed the tower of abstraction. And in this last stretch, you sat down and told the machine what to do, in C, the same machine, the same loop, the same mailboxes, now bending to instructions you wrote. You closed the whole circle, from "I have no idea how this works" to a CPU obeying your code.
So let's settle a debt. Remember your very first assignment, all the way back in "What you'll actually learn"?
The exercise you've been carrying: Explain, in complete detail, everything that happens between pressing the 'A' key and the letter A appearing on screen. Go dig out the answer you wrote on day one. Read it again.
You still can't explain all of it, and that's honest, some of it (the operating system, the keyboard driver, the graphics hardware) lives in layers we deliberately saved for later courses. But look how much you can explain now that you couldn't then. Pressing the key sends a signal; that signal becomes a number (a code for 'A', and you now know a char is just a number, that 'A' is really 65); that number rides the buses into memory, sits in an addressed mailbox; the CPU fetches, decodes, and executes instructions, real machine code, that decide what to do with it; layers of abstraction hand it upward; and eventually instructions push pixels until an "A" glows on your screen. You've gone from a blank stare to pointing confidently at most of the pieces. The box is less magic now, and crucially, it's less magic by choice. The bits still hidden from you are hidden because you haven't cracked those lids yet, not because you're stuck. That, right there, is the whole difference between a user and an engineer. That was the entire point.
First and non-negotiable: prove your toolchain runs. Before next session, get
hello, worldto actually compile and run, both in OnlineGDB (browser, zero setup) and, if you can, locally by installing a compiler and runninggcc hello.cyourself from the terminal. If your own machine can compile and run C, you're ready for everything ahead. If it can't, that's what we sort out first thing next time, don't suffer in silence.
Then a few small programs to actually write (no copying, type them, break them, fix them):
double.)% and an if to say whether it's even or odd.int max(int a, int b) that returns the larger of two numbers, then call it from main. Small, sharp, does one thing well. Very Unix of you.The full set of exercises (in Romanian) and all the tool links live on the CS1 resources page, go there for the complete list and the challenges.
For the brave (tying it all back): pick one. (a) Rewrite that "read two numbers and add them" Little Man Computer program in C, and notice how much shorter and clearer the high-level version is, that's abstraction earning its keep. (b) Or sit with the Halting Problem and write up, in your own words, why no program can detect every infinite loop, the proof's in the Turing section, and explaining it back is how you truly own it.
And that's CS1. Next time we go deeper and dirtier: what's actually inside a byte, how memory is really built, the digital electronics to build logic gates from the components you soldered in E1, and the part of C that gives people gray hair (pointers, and talking to memory directly, that little & finally explained in full). You've got the foundation now. Time to build on it.