Instant Download Beej S Guide To C Programming Brian Beej Jorgensen Hall PDF All Chapter
Instant Download Beej S Guide To C Programming Brian Beej Jorgensen Hall PDF All Chapter
Instant Download Beej S Guide To C Programming Brian Beej Jorgensen Hall PDF All Chapter
com
https://ebookmeta.com/product/beej-s-guide-to-c-
programming-brian-beej-jorgensen-hall-4/
OR CLICK BUTTON
DOWLOAD EBOOK
https://ebookmeta.com/product/beej-s-guide-to-c-programming-
brian-beej-jorgensen-hall-5/
https://ebookmeta.com/product/beej-s-guide-to-c-programming-
brian-beej-jorgensen-hall-6/
https://ebookmeta.com/product/beej-s-guide-to-c-programming-
brian-beej-jorgensen-hall/
https://ebookmeta.com/product/beej-s-guide-to-c-programming-
brian-beej-jorgensen-hall-4/
Beej s Guide to C Programming Brian Beej Jorgensen Hall
https://ebookmeta.com/product/beej-s-guide-to-c-programming-
brian-beej-jorgensen-hall-3/
https://ebookmeta.com/product/effective-perl-programming-2nd-
edition-joseph-n-hall-joshua-mcadams-brian-d-foy/
https://ebookmeta.com/product/software-testing-a-craftsman-s-
approach-5th-edition-paul-c-jorgensen/
https://ebookmeta.com/product/c-programming-language-the-
beginner-s-guide-2020th-edition-unknown/
https://ebookmeta.com/product/let-us-c-authentic-guide-to-c-
programming-language-19th-edition-yashavant-kanetkar/
Beej’s Guide to C Programming
1 Foreword 1
1.1 Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 How to Read This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Platform and Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Official Homepage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.5 Email Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.6 Mirroring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.7 Note for Translators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.8 Copyright and Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.9 Dedication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Hello, World! 5
2.1 What to Expect from C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Hello, World! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Compilation Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4 Building with gcc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.5 Building with clang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.6 Building from IDEs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.7 C Versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4 Functions 25
4.1 Passing by Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2 Function Prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3 Empty Parameter Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5 Pointers—Cower In Fear! 29
5.1 Memory and Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.2 Pointer Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
ii
CONTENTS iii
5.3 Dereferencing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.4 Passing Pointers as Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.5 The NULL Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.6 A Note on Declaring Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.7 sizeof and Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6 Arrays 37
6.1 Easy Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.2 Getting the Length of an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.3 Array Initializers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.4 Out of Bounds! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.5 Multidimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.6 Arrays and Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.6.1 Getting a Pointer to an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.6.2 Passing Single Dimensional Arrays to Functions . . . . . . . . . . . . . . . . . 42
6.6.3 Changing Arrays in Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.6.4 Passing Multidimensional Arrays to Functions . . . . . . . . . . . . . . . . . . 44
7 Strings 45
7.1 String Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.2 String Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.3 String Variables as Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.4 String Initializers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.5 Getting String Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.6 String Termination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.7 Copying a String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
8 Structs 51
8.1 Declaring a Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.2 Struct Initializers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.3 Passing Structs to Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.4 The Arrow Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.5 Copying and Returning structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
8.6 Comparing structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
9 File Input/Output 55
9.1 The FILE* Data Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
9.2 Reading Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
9.3 End of File: EOF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
9.3.1 Reading a Line at a Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
9.4 Formatted Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
9.5 Writing Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
9.6 Binary File I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
9.6.1 struct and Number Caveats . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
13 Scope 83
13.1 Block Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
13.1.1 Where To Define Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
13.1.2 Variable Hiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
13.2 File Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
13.3 for-loop Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
13.4 A Note on Function Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
27.6 A Quick Note on UTF-8 Before We Swerve into the Weeds . . . . . . . . . . . . . . 192
27.7 Different Character Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
27.7.1 Multibyte Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
27.7.2 Wide Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
27.8 Using Wide Characters and wchar_t . . . . . . . . . . . . . . . . . . . . . . . . . . 194
27.8.1 Multibyte to wchar_t Conversions . . . . . . . . . . . . . . . . . . . . . . . . 195
27.9 Wide Character Functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.1 wint_t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.2 I/O Stream Orientation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.3 I/O Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.4 Type Conversion Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
27.9.5 String and Memory Copying Functions . . . . . . . . . . . . . . . . . . . . . 197
27.9.6 String and Memory Comparing Functions . . . . . . . . . . . . . . . . . . . . 197
27.9.7 String Searching Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
27.9.8 Length/Miscellaneous Functions . . . . . . . . . . . . . . . . . . . . . . . . . 198
27.9.9 Character Classification Functions . . . . . . . . . . . . . . . . . . . . . . . . 198
27.10 Parse State, Restartable Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
27.11 Unicode Encodings and C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
27.11.1 UTF-8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
27.11.2 UTF-16, UTF-32, char16_t, and char32_t . . . . . . . . . . . . . . . . . . . 201
27.11.3 Multibyte Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
27.11.4 Third-Party Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
31 goto 219
31.1 A Simple Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
31.2 Labeled continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
31.3 Bailing Out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
31.4 Labeled break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
31.5 Multi-level Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
31.6 Tail Call Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
viii CONTENTS
39 Multithreading 261
39.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
39.2 Things You Can Do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
39.3 Data Races and the Standard Library . . . . . . . . . . . . . . . . . . . . . . . . . . 262
39.4 Creating and Waiting for Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
39.5 Detaching Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
39.6 Thread Local Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
39.6.1 _Thread_local Storage-Class . . . . . . . . . . . . . . . . . . . . . . . . . 268
39.6.2 Another Option: Thread-Specific Storage . . . . . . . . . . . . . . . . . . . . 269
39.7 Mutexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
39.7.1 Different Mutex Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
39.8 Condition Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
39.8.1 Timed Condition Wait . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
39.8.2 Broadcast: Wake Up All Waiting Threads . . . . . . . . . . . . . . . . . . . . 278
39.9 Running a Function One Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
40 Atomics 279
40.1 Testing for Atomic Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
40.2 Atomic Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
40.3 Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
40.4 Acquire and Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
40.5 Sequential Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
40.6 Atomic Assignments and Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
40.7 Library Functions that Automatically Synchronize . . . . . . . . . . . . . . . . . . . 285
40.8 Atomic Type Specifier, Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
40.9 Lock-Free Atomic Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
40.9.1 Signal Handlers and Lock-Free Atomics . . . . . . . . . . . . . . . . . . . . . 288
40.10 Atomic Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
40.11 Atomic structs and unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
40.12 Atomic Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
40.13 Memory Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
40.13.1 Sequential Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.2 Acquire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.3 Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.4 Consume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.5 Acquire/Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.6 Relaxed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.14 Fences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
40.15 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Foreword
1.1 Audience
This guide assumes that you’ve already got some programming knowledge under your belt from another
language, such as Python2 , JavaScript3 , Java4 , Rust5 , Go6 , Swift7 , etc. (Objective-C8 devs will have a
particularly easy time of it!)
We’re going to assume you know what variables are, what loops do, how functions work, and so on.
1
https://www.ioccc.org/
2
https://en.wikipedia.org/wiki/Python_(programming_language)
3
https://en.wikipedia.org/wiki/JavaScript
4
https://en.wikipedia.org/wiki/Java_(programming_language)
5
https://en.wikipedia.org/wiki/Rust_(programming_language)
6
https://en.wikipedia.org/wiki/Go_(programming_language)
7
https://en.wikipedia.org/wiki/Swift_(programming_language)
8
https://en.wikipedia.org/wiki/Objective-C
1
2 Chapter 1. Foreword
If that’s not you for whatever reason the best I can hope to provide is some honest entertainment for your
reading pleasure. The only thing I can reasonably promise is that this guide won’t end on a cliffhanger…
or will it?
If you don’t get a response, hack on it some more, try to find the answer, and if it’s still elusive, then write
me again with the information you’ve found and hopefully it will be enough for me to help out.
Now that I’ve badgered you about how to write and not write me, I’d just like to let you know that I fully
appreciate all the praise the guide has received over the years. It’s a real morale boost, and it gladdens me
to hear that it is being used for good! :-) Thank you!
1.6 Mirroring
You are more than welcome to mirror this site, whether publicly or privately. If you publicly mirror the
site and want me to link to it from the main page, drop me a line at [email protected].
1.9 Dedication
The hardest things about writing these guides are:
• Learning the material in enough detail to be able to explain it
• Figuring out the best way to explain it clearly, a seemingly-endless iterative process
• Putting myself out there as a so-called authority, when really I’m just a regular human trying to
make sense of it all, just like everyone else
• Keeping at it when so many other things draw my attention
A lot of people have helped me through this process, and I want to acknowledge those who have made
this book possible.
• Everyone on the Internet who decided to help share their knowledge in one form or another. The
free sharing of instructive information is what makes the Internet the great place that it is.
• The volunteers at cppreference.com16 who provide the bridge that leads from the spec to the real
world.
16
https://en.cppreference.com/
4 Chapter 1. Foreword
• The helpful and knowledgeable folks on comp.lang.c17 and r/C_Programming18 who got me through
the tougher parts of the language.
• Everyone who submitted corrections and pull-requests on everything from misleading instructions
to typos.
Thank you! ♥
17
https://groups.google.com/g/comp.lang.c
18
https://www.reddit.com/r/C_Programming/
Chapter 2
Hello, World!
5
6 Chapter 2. Hello, World!
So get ready for a rollicking adventure as close to the core of the computer as you can get without assembly,
in the most influential computer language of all time7 . Hang on!
3 #include <stdio.h>
4
5 int main(void)
6 {
7 printf("Hello, World!\n"); // Actually do the work here
8 }
We’re going to don our long-sleeved heavy-duty rubber gloves, grab a scalpel, and rip into this thing to
see what makes it tick. So, scrub up, because here we go. Cutting very gently…
Let’s get the easy thing out of the way: anything between the digraphs /* and */ is a comment and will
be completely ignored by the compiler. Same goes for anything on a line after a //. This allows you
to leave messages to yourself and others, so that when you come back and read your code in the distant
future, you’ll know what the heck it was you were trying to do. Believe me, you will forget; it happens.
Now, what is this #include? GROSS! Well, it tells the C Preprocessor to pull the contents of another file
and insert it into the code right there.
Wait—what’s a C Preprocessor? Good question. There are two stages8 to compilation: the preprocessor
and the compiler. Anything that starts with pound sign, or “octothorpe”, (#) is something the preprocessor
operates on before the compiler even gets started. Common preprocessor directives, as they’re called, are
#include and #define. More on that later.
Before we go on, why would I even begin to bother pointing out that a pound sign is called an octothorpe?
The answer is simple: I think the word octothorpe is so excellently funny, I have to gratuitously spread its
name around whenever I get the opportunity. Octothorpe. Octothorpe, octothorpe, octothorpe.
So anyway. After the C preprocessor has finished preprocessing everything, the results are ready for
the compiler to take them and produce assembly code9 , machine code10 , or whatever it’s about to do.
Machine code is the “language” the CPU understands, and it can understand it very rapidly. This is one
of the reasons C programs tend to be quick.
Don’t worry about the technical details of compilation for now; just know that your source runs through
the preprocessor, then the output of that runs through the compiler, then that produces an executable for
you to run.
What about the rest of the line? What’s <stdio.h>? That is what is known as a header file. It’s the
dot-h at the end that gives it away. In fact it’s the “Standard I/O” (stdio) header file that you will grow
to know and love. It gives us access to a bunch of I/O functionality11 . For our demo program, we’re
outputting the string “Hello, World!”, so we in particular need access to the printf() function to do
this. The <stdio.h> file gives us this access. Basically, if we tried to use printf() without #include
<stdio.h>, the compiler would have complained to us about it.
How did I know I needed to #include <stdio.h> for printf()? Answer: it’s in the documentation.
If you’re on a Unix system, man 3 printf and it’ll tell you right at the top of the man page what header
files are required. Or see the reference section in this book. :-)
7
I know someone will fight me on that, but it’s gotta be at least in the top three, right?
8
Well, technically there are more than two, but hey, let’s pretend there are two—ignorance is bliss, right?
9
https://en.wikipedia.org/wiki/Assembly_language
10
https://en.wikipedia.org/wiki/Machine_code
11
Technically, it contains preprocessor directives and function prototypes (more on that later) for common input and output needs.
2.3. Compilation Details 7
Holy moly. That was all to cover the first line! But, let’s face it, it has been completely dissected. No
mystery shall remain!
So take a breather…look back over the sample code. Only a couple easy lines to go.
Welcome back from your break! I know you didn’t really take a break; I was just humoring you.
The next line is main(). This is the definition of the function main(); everything between the squirrelly
braces ({ and }) is part of the function definition.
(How do you call a different function, anyway? The answer lies in the printf() line, but we’ll get to
that in a minute.)
Now, the main function is a special one in many ways, but one way stands above the rest: it is the function
that will be called automatically when your program starts executing. Nothing of yours gets called before
main(). In the case of our example, this works fine since all we want to do is print a line and exit.
Oh, that’s another thing: once the program executes past the end of main(), down there at the closing
squirrelly brace, the program will exit, and you’ll be back at your command prompt.
So now we know that that program has brought in a header file, stdio.h, and declared a main() function
that will execute when the program is started. What are the goodies in main()?
I am so happy you asked. Really! We only have the one goodie: a call to the function printf(). You
can tell this is a function call and not a function definition in a number of ways, but one indicator is the
lack of squirrelly braces after it. And you end the function call with a semicolon so the compiler knows
it’s the end of the expression. You’ll be putting semicolons after almost everything, as you’ll see.
You’re passing one argument to the function printf(): a string to be printed when you call it. Oh, yeah—
we’re calling a function! We rock! Wait, wait—don’t get cocky. What’s that crazy \n at the end of the
string? Well, most characters in the string will print out just like they are stored. But there are certain
characters that you can’t print on screen well that are embedded as two-character backslash codes. One of
the most popular is \n (read “backslash-N” or simply “newline”) that corresponds to the newline character.
This is the character that causes further printing to continue at the beginning of the next line instead of the
current. It’s like hitting return at the end of the line.
So copy that code into a file called hello.c and build it. On a Unix-like platform (e.g. Linux, BSD, Mac,
or WSL), from the command line you’ll build with a command like so:
gcc -o hello hello.c
(The leading ./ tells the shell to “run from the current directory”.)
And see what happens:
Hello, World!
machine can execute. Java devs are used to compilation, but that produces bytecode for the Java Virtual
Machine.
When compiling C, machine code is generated. This is the 1s and 0s that can be executed directly and
speedily by the CPU.
Languages that typically aren’t compiled are called interpreted languages. But as we men-
tioned with Java and Python, they also have a compilation step. And there’s no rule saying
that C can’t be interpreted. (There are C interpreters out there!) In short, it’s a bunch of gray
areas. Compilation in general is just taking source code and turning it into another, more
easily-executed form.
The C compiler is the program that does the compilation.
As we’ve already said, gcc is a compiler that’s installed on a lot of Unix-like operating systems12 . And
it’s commonly run from the command line in a terminal, but not always. You can run it from your IDE,
as well.
So how do we do command line builds?
The -o means “output to this file”13 . And there’s hello.c at the end, the name of the file we want to
compile.
If your source is broken up into multiple files, you can compile them all together (almost as if they were
one file, but the rules are actually more complex than that) by putting all the .c files on the command line:
gcc -o awesomegame ui.c characters.c npc.c items.c
2.7 C Versions
C has come a long way over the years, and it had many named version numbers to describe which dialect
of the language you’re using.
These generally refer to the year of the specification.
The most famous are C89, C99, C11, and C2x. We’ll focus on the latter in this book.
But here’s a more complete table:
Version Description
K&R C 1978, the original. Named after Brian Kernighan and Dennis Ritchie.
Ritchie designed and coded the language, and Kernighan co-authored the
book on it. You rarely see original K&R code today. If you do, it’ll look
odd, like Middle English looks odd to modern English readers.
C89, ANSI C, C90 In 1989, the American National Standards Institute (ANSI) produced a C
language specification that set the tone for C that persists to this day. A
year later, the reins were handed to the International Organization for
Standardization (ISO) that produced the identical C90.
C95 A rarely-mentioned addition to C89 that included wide character support.
C99 The first big overhaul with lots of language additions. The thing most
people remember is the addition of //-style comments. This is the most
popular version of C in use as of this writing.
C11 This major version update includes Unicode support and multi-threading.
Be advised that if you start using these language features, you might be
sacrificing portability with places that are stuck in C99 land. But, honestly,
1999 is getting to be a while back now.
C17, C18 Bugfix update to C11. C17 seems to be the official name, but the
publication was delayed until 2018. As far as I can tell, these two are
interchangeable, with C17 being preferred.
C2x What’s coming next! Expected to eventually become C23.
You can force GCC to use one of these standards with the -std= command line argument. If you want it
to be picky about the standard, add -pedantic.
For example:
gcc -std=c11 -pedantic foo.c
For this book, I compile programs for C2x with all warnings set:
gcc -Wall -Wextra -std=c2x -pedantic foo.c
10 Chapter 2. Hello, World!
Chapter 3
3.1 Variables
It’s said that “variables hold values”. But another way to think about it is that a variable is a human-
readable name that refers to some data in memory.
We’re going to take a second here and take a peek down the rabbit hole that is pointers. Don’t worry about
it.
You can think of memory as a big array of bytes1 . Data is stored in this “array”2 . If a number is larger than
a single byte, it is stored in multiple bytes. Because memory is like an array, each byte of memory can be
referred to by its index. This index into memory is also called an address, or a location, or a pointer.
When you have a variable in C, the value of that variable is in memory somewhere, at some address. Of
course. After all, where else would it be? But it’s a pain to refer to a value by its numeric address, so we
make a name for it instead, and that’s what the variable is.
The reason I’m bringing all this up is twofold:
1. It’s going to make it easier to understand pointer variables later—they’re variables that hold the
address of other variables!
2. Also, it’s going to make it easier to understand pointers later.
So a variable is a name for some data that’s stored in memory at some address.
11
12 Chapter 3. Variables and Statements
• You can’t start a variable name with an underscore followed by a capital A-Z.
For Unicode, just try it. There are some rules in the spec in §D.2 that talk about which Unicode codepoint
ranges are allowed in which parts of identifiers, but that’s too much to write about here and is probably
something you’ll never have to think about anyway.
C makes an effort to convert automatically between most numeric types when you ask it to. But other
than that, all conversions are manual, notably between string and numeric.
Almost all of the types in C are variants on these types.
Before you can use a variable, you have to declare that variable and tell C what type the variable holds.
Once declared, the type of variable cannot be changed later at runtime. What you set it to is what it is
until it falls out of scope and is reabsorbed into the universe.
Let’s take our previous “Hello, world” code and add a couple variables to it:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int i; // Holds signed integers, e.g. -3, -2, 0, 1, 10
6 float f; // Holds signed floating point numbers, e.g. -3.1416
7
There! We’ve declared a couple of variables. We haven’t used them yet, and they’re both uninitialized.
One holds an integer number, and the other holds a floating point number (a real number, basically, if you
have a math background).
Uninitialized variables have indeterminate value5 . They have to be initialized or else you must assume
they contain some nonsense number.
This is one of the places C can “get you”. Much of the time, in my experience, the indeter-
minate value is zero… but it can vary from run to run! Never assume the value will be zero,
even if you see it is. Always explicitly initialize variables to some value before you use them6 .
What’s this? You want to store some numbers in those variables? Insanity!
Let’s go ahead and do that:
3
I’m lying here a little. Technically 3.14159 is of type double, but we’re not there yet and I want you to associate float with
“Floating Point”, and C will happily coerce that type into a float. In short, don’t worry about it until later.
4
Read this as “pointer to a char” or “char pointer”. “Char” for character. Though I can’t find a study, it seems anecdotally most
people pronounce this as “char”, a minority say “car”, and a handful say “care”. We’ll talk more about pointers later.
5
Colloquially, we say they have “random” values, but they aren’t truly—or even pseudo-truly—random numbers.
6
This isn’t strictly 100% true. When we get to learning about static storage duration, you’ll find the some variables are initialized
to zero automatically. But the safe thing to do is always initialize them.
3.1. Variables 13
1 int main(void)
2 {
3 int i;
4
7 printf("Hello, World!\n");
8 }
3 int main(void)
4 {
5 int i = 2;
6 float f = 3.14;
7 char *s = "Hello, world!"; // char * ("char pointer") is the string type
8
In this way, printf() might be similar to various types of format strings or parameterized strings in other
languages you’re familiar with.
Historically, C didn’t have a Boolean type, and some might argue it still doesn’t.
In C, 0 means “false”, and non-zero means “true”.
So 1 is true. And -37 is true. And 0 is false.
You can just declare Boolean types as ints:
int x = 1;
if (x) {
printf("x is true!\n");
}
If you #include <stdbool.h>, you also get access to some symbolic names that might make things
look more familiar, namely a bool type and true and false values:
1 #include <stdio.h>
2 #include <stdbool.h>
14 Chapter 3. Variables and Statements
4 int main(void) {
5 bool x = true;
6
7 if (x) {
8 printf("x is true!\n");
9 }
10 }
But these are identical to using integer values for true and false. They’re just a facade to make things look
nice.
3.2.1 Arithmetic
Hopefully these are familiar:
i = i + 3; // Addition (+) and assignment (=) operators, add 3 to i
i = i - 8; // Subtraction, subtract 8 from i
i = i * 9; // Multiplication
i = i / 2; // Division
i = i % 5; // Modulo (division remainder)
There are shorthand variants for all of the above. Each of those lines could more tersely be written as:
i += 3; // Same as "i = i + 3", add 3 to i
i -= 8; // Same as "i = i - 8"
i *= 9; // Same as "i = i * 9"
i /= 2; // Same as "i = i / 2"
i %= 5; // Same as "i = i % 5"
There is no exponentiation. You’ll have to use one of the pow() function variants from math.h.
Let’s get into some of the weirder stuff you might not have in your other languages!
What a mess! You’ll get used to it the more you read it. To help out a bit, I’ll rewrite the above expression
using if statements:
// This expression:
if (x > 10)
y += 17;
else
y += 37;
3.2. Operators and Expressions 15
Compare those two until you see each of the components of the ternary operator.
The %s format specifier in printf() means print a string. If the expression x % 2 evaluates to 0, the
value of the entire ternary expression evaluates to the string "even". Otherwise it evaluates to the string
"odd". Pretty cool!
It’s important to note that the ternary operator isn’t flow control like the if statement is. It’s just an
expression that evaluates to a value.
but they’re more subtly different than that, the clever scoundrels.
With pre-increment and pre-decrement, the value of the variable is incremented or decremented before
the expression is evaluated. Then the expression is evaluated with the new value.
With post-increment and post-decrement, the value of the expression is first computed with the value as-is,
and then the value is incremented or decremented after the value of the expression has been determined.
This technique is used frequently with array and pointer access and manipulation. It gives you a way to
use the value in a variable, and also increment or decrement that value before or after it is used.
But by far the most common place you’ll see this is in a for loop:
for (i = 0; i < 10; i++)
printf("i is %d\n", i);
Seems a bit silly, since you could just replace the comma with a semicolon, right?
x = 10; y = 20; // First assign 10 to x, then 20 to y
But that’s a little different. The latter is two separate expressions, while the former is a single expression!
With the comma operator, the value of the comma expression is the value of the rightmost expression:
x = (1, 2, 3);
But even that’s pretty contrived. One common place the comma operator is used is in for loops to do
multiple things in each section of the statement:
for (i = 0, j = 10; i < 100; i++, j++)
printf("%d, %d\n", i, j);
Don’t mix up assignment = with comparison ==! Use two equals to compare, one to assign.
We can use the comparison expressions with if statements:
if (a <= 10)
printf("Success!\n");
! has higher precedence than the other Boolean operators, so we have to use parentheses in that case.
Remember: it’s the size in bytes of the type of the expression, not the size of the expression itself. That’s
why the size of 2+7 is the same as the size of a—they’re both type int. We’ll revisit this number 4 in the
very next block of code…
…Where we’ll see you can take the sizeof a type (note the parentheses are required around a type name,
unlike an expression):
printf("%zu\n", sizeof(int)); // Prints 4 on my system
printf("%zu\n", sizeof(char)); // Prints 1 on all systems
It’s important to note that sizeof is a compile-time operation8 . The result of the expression is determined
entirely at compile-time, not at runtime.
We’ll make use of this later on.
First, a general forward-looking note about statements and blocks of statements brought to you by your
local friendly C developer:
After something like an if or while statement, you can either put a single statement to be executed, or a
block of statements to all be executed in sequence.
This is also sometimes written on a separate line. (Whitespace is largely irrelevant in C—it’s not like
Python.)
if (x == 10)
printf("x is 10\n");
But what if you want multiple things to happen due to the conditional? You can use squirrelly braces to
mark a block or compound statement.
if (x == 10) {
printf("x is 10\n");
printf("And also this happens when x is 10\n");
}
It’s a really common style to always use squirrelly braces even if they aren’t necessary:
if (x == 10) {
printf("x is 10\n");
}
Some devs feel the code is easier to read and avoids errors like this where things visually look like they’re
in the if block, but actually they aren’t.
// BAD ERROR EXAMPLE
if (x == 10)
printf("This happens if x is 10\n");
printf("This happens ALWAYS\n"); // Surprise!! Unconditional!
while and for and the other looping constructs work the same way as the examples above. If you want
to do multiple things in a loop or after an if, wrap them up in squirrelly braces.
In other words, the if is going to run the one thing after the if. And that one thing can be a single
statement or a block of statements.
if (i > 10) {
printf("Yes, i is greater than 10.\n");
printf("And this will also print if i is greater than 10.\n");
}
In the example code, the message will print if i is greater than 10, otherwise execution continues to the next
line. Notice the squirrley braces after the if statement; if the condition is true, either the first statement
or expression right after the if will be executed, or else the collection of code in the squirlley braces after
the if will be executed. This sort of code block behavior is common to all statements.
3.3. Flow Control 19
Of course, because C is fun this way, you can also do something if the condition is false with an else
clause on your if:
int i = 99;
if (i == 10)
printf("i is 10!\n");
else {
printf("i is decidedly not 10.\n");
printf("Which irritates me a little, frankly.\n");
}
And you can even cascade these to test a variety of conditions, like this:
int i = 99;
if (i == 10)
printf("i is 10!\n");
else if (i == 20)
printf("i is 20!\n");
else if (i == 99) {
printf("i is 99! My favorite\n");
printf("I can't tell you how happy I am.\n");
printf("Really.\n");
}
else
printf("i is some crazy number I've never heard of.\n");
Though if you’re going that route, be sure to check out the switch statement for a potentially better
solution. The catch is switch only works with equality comparisons with constant numbers. The above
if-else cascade could check inequality, ranges, variables, or anything else you can craft in a conditional
expression.
Let’s do one!
// Print the following output:
//
// i is now 0!
// i is now 1!
// [ more of the same between 2 and 7 ]
// i is now 8!
// i is now 9!
i = 0;
printf("All done!\n");
That gets you a basic loop. C also has a for loop which would have been cleaner for that example.
A not-uncommon use of while is for infinite loops where you repeat while true:
20 Chapter 3. Variables and Statements
while (1) {
printf("1 is always true, so this repeats forever.\n");
}
They are basically the same, except if the loop condition is false on the first pass, do-while will execute
once, but while won’t execute at all. In other words, the test to see whether or not to execute the block
happens at the end of the block with do-while. It happens at the beginning of the block with while.
Let’s see by example:
// Using a while statement:
i = 10;
i = 10;
// this is executed once, because the loop condition is not checked until
// after the body of the loop runs:
do {
printf("do-while: i is %d\n", i);
i++;
} while (i < 10);
printf("All done!\n");
Notice that in both cases, the loop condition is false right away. So in the while, the loop fails, and
the following block of code is never executed. With the do-while, however, the condition is checked
after the block of code executes, so it always executes at least once. In this case, it prints the message,
increments i, then fails the condition, and continues to the “All done!” output.
The moral of the story is this: if you want the loop to execute at least once, no matter what the loop
condition, use do-while.
All these examples might have been better done with a for loop. Let’s do something less deterministic—
repeat until a certain random number comes up!
1 #include <stdio.h> // For printf
2 #include <stdlib.h> // For rand
3
4 int main(void)
5 {
6 int r;
7
8 do {
9 r = rand() % 100; // Get a random number between 0 and 99
10 printf("%d\n", r);
3.3. Flow Control 21
Side note: did you run that more than once? If you did, did you notice the same sequence of numbers
came up again. And again. And again? This is because rand() is a pseudorandom number generator that
must be seeded with a different number in order to generate a different sequence. Look up the srand()9
function for more details.
i = 0;
while (i < 10) {
printf("i is %d\n", i);
i++;
}
That’s right, folks—they do exactly the same thing. But you can see how the for statement is a little more
compact and easy on the eyes. (JavaScript users will fully appreciate its C origins at this point.)
It’s split into three parts, separated by semicolons. The first is the initialization, the second is the loop
condition, and the third is what should happen at the end of the block if the loop condition is true. All
three of these parts are optional.
for (initialize things; loop if this is true; do this after each loop)
Note that the loop will not execute even a single time if the loop condition starts off false.
for-loop fun fact!
You can use the comma operator to do multiple things in each clause of the for loop!
for (i = 0, j = 999; i < 10; i++, j--) {
printf("%d, %d\n", i, j);
}
9
https://beej.us/guide/bgclr/html/split/stdlib.html#man-srand
22 Chapter 3. Variables and Statements
Let’s do an example where the user enters a number of goats and we print out a gut-feel of how many
goats that is.
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int goat_count;
6
10 switch (goat_count) {
11 case 0:
12 printf("You have no goats.\n");
13 break;
14
15 case 1:
16 printf("You have a singular goat.\n");
17 break;
18
19 case 2:
20 printf("You have a brace of goats.\n");
21 break;
22
23 default:
24 printf("You have a bona fide plethora of goats!\n");
25 break;
26 }
27 }
In that example, if the user enters, say, 2, the switch will jump to the case 2 and execute from there.
When (if) it hits a break, it jumps out of the switch.
Also, you might see that default label there at the bottom. This is what happens when no cases match.
Every case, including default, is optional. And they can occur in any order, but it’s really typical for
default, if any, to be listed last.
• if-else can do things like relational conditionals like < and >= and floating point and other types,
while switch cannot.
There’s one more neat thing about switch that you sometimes see that is quite interesting: fall through.
Remember how break causes us to jump out of the switch?
Well, what happens if we don’t break?
Turns out we just keep on going into the next case! Demo!
switch (x) {
case 1:
printf("1\n");
// Fall through!
case 2:
printf("2\n");
break;
case 3:
printf("3\n");
break;
}
If x == 1, this switch will first hit case 1, it’ll print the 1, but then it just continues on to the next line
of code… which prints 2!
And then, at last, we hit a break so we jump out of the switch.
if x == 2, then we just hit the case 2, print 2, and break as normal.
Not having a break is called fall through.
ProTip: ALWAYS put a comment in the code where you intend to fall through, like I did above. It will
save other programmers from wondering if you meant to do that.
In fact, this is one of the common places to introduce bugs in C programs: forgetting to put a break in
your case. You gotta do it if you don’t want to just roll into the next case10 .
Earlier I said that switch works with integer types—keep it that way. Don’t use floating point or string
types in there. One loophole-ish thing here is that you can use character types because those are secretly
integers themselves. So this is perfectly acceptable:
char c = 'b';
switch (c) {
case 'a':
printf("It's 'a'!\n");
break;
case 'b':
printf("It's 'b'!\n");
break;
case 'c':
printf("It's 'c'!\n");
break;
}
Finally, you can use enums in switch since they are also integer types. But more on that in the enum
chapter.
10
This was considered such a hazard that the designers of the Go Programming Language made break the default; you have to
explicitly use Go’s fallthrough statement if you want to fall into the next case.
24 Chapter 3. Variables and Statements
Chapter 4
Functions
“Sir, not in an environment such as this. That’s why I’ve also been programmed for over thirty
secondary functions that—”
—C3PO, before being rudely interrupted, reporting a now-unimpressive number of additional
functions, Star Wars script
Very much like other languages you’re used to, C has the concept of functions.
Functions can accept a variety of arguments and return a value. One important thing, though: the argu-
ments and return value types are predeclared—because that’s how C likes it!
Let’s take a look at a function. This is a function that takes an int as an argument, and returns an int.
1 #include <stdio.h>
2
Before I forget, notice that I defined the function before I used it. If I hadn’t done that, the
compiler wouldn’t know about it yet when it compiles main() and it would have given an
unknown function call error. There is a more proper way to do the above code with function
prototypes, but we’ll talk about that later.
25
26 Chapter 4. Functions
5 void hello(void)
6 {
7 printf("Hello, world!\n");
8 }
9
10 int main(void)
11 {
12 hello(); // Prints "Hello, world!"
13 }
3 void increment(int a)
4 {
5 a++;
6 }
7
8 int main(void)
9 {
10 int i = 10;
11
12 increment(i);
13
At first glance, it looks like i is 10, and we pass it to the function increment(). There the value gets
incremented, so when we print it, it must be 11, right?
“Get used to disappointment.”
—Dread Pirate Roberts, The Princess Bride
But it’s not 11—it prints 10! How?
4.2. Function Prototypes 27
It’s all about the fact that the expressions you pass to functions get copied onto their corresponding pa-
rameters. The parameter is a copy, not the original.
So i is 10 out in main(). And we pass it to increment(). The corresponding parameter is called a in
that function.
And the copy happens, as if by assignment. Loosely, a = i. So at that point, a is 10. And out in main(),
i is also 10.
Then we increment a to 11. But we’re not touching i at all! It remains 10.
Finally, the function is complete. All its local variables are discarded (bye, a!) and we return to main(),
where i is still 10.
And we print it, getting 10, and we’re done.
This is why in the previous example with the plus_one() function, we returned the locally modified
value so that we could see it again in main().
Seems a little bit restrictive, huh? Like you can only get one piece of data back from a function, is what
you’re thinking. There is, however, another way to get data back; C folks call it passing by reference and
that’s a story we’ll tell another time.
But no fancy-schmancy name will distract you from the fact that EVERYTHING you pass to a function
WITHOUT EXCEPTION is copied into its corresponding parameter, and the function operates on that
local copy, NO MATTER WHAT. Remember that, even when we’re talking about this so-called passing
by reference.
5 int main(void)
6 {
7 int i;
8
12 i = foo();
13
If you don’t declare your function before you use it (either with a prototype or its definition), you’re
performing something called an implicit declaration. This was allowed in the first C standard (C89), and
that standard has rules about it, but is no longer allowed today. And there is no legitimate reason to rely
on it in new code.
You might notice something about the sample code we’ve been using… That is, we’ve been using the
good old printf() function without defining it or declaring a prototype! How do we get away with this
lawlessness? We don’t, actually. There is a prototype; it’s in that header file stdio.h that we included
with #include, remember? So we’re still legit, officer!
While the spec spells out that the behavior in this instance is as-if you’d indicated void (C11 §6.7.6.3¶14),
the void type is there for a reason. Use it.
But in the case of a function prototype, there is a significant difference between using void and not:
void foo();
void foo(void); // Not the same!
Leaving void out of the prototype indicates to the compiler that there is no additional information about
the parameters to the function. It effectively turns off all that type checking.
With a prototype definitely use void when you have an empty parameter list.
1
Never say “never”.
Chapter 5
Pointers—Cower In Fear!
Memory Fun Facts: When you have a data type (like your typical int) that uses more than a
byte of memory, the bytes that make up the data are always adjacent to one another in memory.
Sometimes they’re in the order that you expect, and sometimes they’re not3 . While C doesn’t
1
Typically. I’m sure there are exceptions out there in the dark corridors of computing history.
2
A byte is a number made up of no more than 8 binary digits, or bits for short. This means in decimal digits just like grandma
used to use, it can hold an unsigned number between 0 and 255, inclusive.
3
The order that bytes come in is referred to as the endianness of the number. The usual suspects are big-endian (with the most
significant byte first) and little-endian (with the most-significant byte last), or, uncommonly now, mixed-endian (with the most-
significant bytes somewhere else).
29
30 Chapter 5. Pointers—Cower In Fear!
guarantee any particular memory order (it’s platform-dependent), it’s still generally possible
to write code in a way that’s platform-independent where you don’t have to even consider
these pesky byte orderings.
So anyway, if we can get on with it and get a drum roll and some foreboding music playing for the
definition of a pointer, a pointer is a variable that holds an address. Imagine the classical score from
2001: A Space Odyssey at this point. Ba bum ba bum ba bum BAAAAH!
Ok, so maybe a bit overwrought here, yes? There’s not a lot of mystery about pointers. They are the
address of data. Just like an int variable can hold the value 12, a pointer variable can hold the address of
data.
This means that all these things mean the same thing, i.e. a number that represents a point in memory:
• Index into memory (if you’re thinking of memory like a big array)
• Address
• Location
I’m going to use these interchangeably. And yes, I just threw location in there because you can never have
enough words that mean the same thing.
And a pointer variable holds that address number. Just like a float variable might hold 3.14159.
Imagine you have a bunch of Post-it® notes all numbered in sequence with their address. (The first one
is at index numbered 0, the next at index 1, and so on.)
In addition to the number representing their positions, you can also write another number of your choice
on each. It could be the number of dogs you have. Or the number of moons around Mars…
…Or, it could be the index of another Post-it note!
If you have written the number of dogs you have, that’s just a regular variable. But if you wrote the index
of another Post-it in there, that’s a pointer. It points to the other note!
Another analogy might be with house addresses. You can have a house with certain qualities, yard, metal
roof, solar, etc. Or you could have the address of that house. The address isn’t the same as the house itself.
One’s a full-blown house, and the other is just a few lines of text. But the address of the house is a pointer
to that house. It’s not the house itself, but it tells you where to find it.
And we can do the same thing in the computer with data. You can have a data variable that’s holding some
value. And that value is in memory at some address. And you could have a different pointer variable hold
the address of that data variable.
It’s not the data variable itself, but, like with a house address, it tells us where to find it.
When we have that, we say we have a “pointer to” that data. And we can follow the pointer to access the
data itself.
(Though it doesn’t seem particularly useful yet, this all becomes indispensable when used with function
calls. Bear with me until we get there.)
So if we have an int, say, and we want a pointer to it, what we want is some way to get the address of
that int, right? After all, the pointer just holds the address of the data. What operator do you suppose
we’d use to find the address of the int?
Well, by a shocking surprise that must come as something of a shock to you, gentle reader, we use the
address-of operator (which happens to be an ampersand: “&”)to find the address of the data. Ampersand.
So for a quick example, we’ll introduce a new format specifier for printf() so you can print a pointer.
You know already how %d prints a decimal integer, yes? Well, %p prints a pointer. Now, this pointer is
going to look like a garbage number (and it might be printed in hexadecimal4 instead of decimal), but it is
merely the index into memory the data is stored in. (Or the index into memory that the first byte of data
is stored in, if the data is multi-byte.) In virtually all circumstances, including this one, the actual value of
the number printed is unimportant to you, and I show it here only for demonstration of the address-of
operator.
4
That is, base 16 with digits 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F.
Another random document with
no related content on Scribd:
[717] 1 Cor. ii. 5.
[718] Heraclitus.
[719] Matt. vii. 7.
[720] Ps. xxii. 6.
[721] 1 John iv. 16.
[722] 1 Cor. i. 9, x. 13.
[723] Matt. xviii. 1.
[724] 1 Cor. iv. 15.
[725] John xiv. 6.
[726] By Plato.
[727] In Plato we have νῷ instead of Θεῷ.
[728] John i. 14.
[729] Matt. vii. 7.
[730] Matt. xi. 12.
[731] Hesiod. first line, “Works and Days,” 285. The other three
are variously ascribed to different authors.
[732] Plato, Alcibiades, book i.
[733] Plato, Republic, vi. p. 678.
[734] Matt. xx. 16.
[735] 1 Cor. viii. 7.
[736] 2 Thess. iii. 1, 2.
[737] Quoted by Socrates in the Phaedo, p. 52.
[738] Ecclus. xxvii. 12.
[739] Prov. x. 14.
[740] Prov. xxvi. 5.
[741] 1 Cor. ix. 22.
[742] Matt. v. 45.
[743] Rom. iii. 29, 30.
[744] 1 Cor. ii. 13.
[745] Bas relief.
[746] Isa. xlv. 3.
[747] Ps. lxxviii. 1, 2.
[748] 1 Cor. ii. 6–8.
[749] 1 Cor. ii. 9, 10.
[750] 1 Cor. ii. 14.
[751] 1 Cor. iii. 1–3.
[752] 1 Cor. iii. 10–13.
[753] Rom. i. 11.
[754] Jer. viii. 7.
[755] Iliad, ix. 311.
[756] Eph. iv. 26.
[757] Ex. xx. 17.
[758] It is so said of the rich: Matt. xix. 23; Mark x. 23; Luke
xviii. 24.
[759] Gen. i. 26.
[760] Matt. xi. 29, 30.
[761] Matt. xviii. 3.
[762] Ps. i. 1.
[763] Gal. v. 25.
[764] 2 Cor. v. 7.
[765] Heb. i. 1.
[766] Rev. v. 6; Isa. xi. 12.
[767] Ἄ—τλας, unsuffering.
[768] The Chaldaic ֵּת יבּוָת א. The Hebrew is ֵּת ָב ה, Sept. κιβωτός,
Vulg. arca.
[769] Eph. v. 23.
[770] 1 Cor. xi. 3; 2 Cor. xi. 31.
[771] And the whole place is very correctly called the Logeum
(λογεῖον), since everything in heaven has been created and
arranged in accordance with right reason (λόγοις) and proportion
(Philo, vol. iii. p. 195, Bohn’s translation).
[772] 1 Cor. xii. 11.
[773] i.e., the oracular breastplate.
[774] Lev. xvi. 23, 24.
[775] This line has given commentators considerable trouble.
Diodorus says that the Telchines—fabled sons of Ocean—were
the first inhabitants of Rhodes.
[776] σύνεσις. Sylburgius, with much probability, conjectures
σύνδεσις, binding together.
[777] Βέδυ, Ζὰψ, Χθὼν, Πλῆκτρον, Σφὶγξ, Κυαξζβὶ, Χθύπτης,
Φλεγμὸς, Δρώψ. On the interpretation of which, much learning
and ingenuity have been expended.
[778] Orpheus.
[779] Lev. xi.; Deut. xiv.
[780] Ps. xvii. 25, 26.
[781] Ex. xv. 1.
[782] Ex. xxi. 33, 36.
[783] Isa. i. 3.
[784] Matt. xi. 13; Luke xvi. 16.
[785] Mark i. 7; Luke iii. 16; John i. 27.
[786] 2 Cor. vi. 14, 15.
[787] 2 Cor. vi. 17, 18.
[788] Eph. iii. 3–5.
[789] Col. i. 9–11.
[790] Col. i. 25–27.
[791] Col. i. 27.
[792] Col. ii. 2, 3.
[793] Col. iv. 2.
[794] Col. iv. 3, 4.
[795] Heb. v. 12, 13, 14, vi. 1.
[796] Isa. ii. 16.
[797] Isa. xlv. 3.
[798] Ps. li. 6, Sept.
[799] Ps. xix. 2, 3.
[800] Rom. xv. 25, 26.
[801] 1 Cor. ii. 6, 7.
[802] 1 Cor. iii. 1–3.
[803] Ps. xxxiv. 8; according to the reading Χριστός for
χρηστός.
[804] 1 Cor. v. 7.
[805] Ex. xxxiii. 18.
[806] Prov. xxx. 2.
[807] Prov. iii. 18.
[808] Ex. xxx. 15, 16, etc.
[809] Gen. xxii. 3, 4.
[810] Or, “the desire of a very good soul,” according to the text
which reads Ἡ ψυχῆς ἀρίστης. The other reading is ἀρίστη.
[811] Baptism.
[812] Isa. lxvi. 1.
[813] Ps. 1. 15.
[814] Acts xvii. 24, 25.
[815] From some apocryphal writing.
[816] ἁγίᾳ is the reading of the text. This is with great
probability supposed to be changed from ἀνῃ, a usual contraction
for ἀνθρωπίνῃ.
[817] Rom. xi. 33.
[818] Alluding to Gen. xviii. 6; the word used is ἐγκρυφίαι,
which Clement, following Philo, from its derivation, takes to signify
occult mysteries.
[819] 1 Cor. vi. 6, 7.
[820] Col. ii. 2, 3.
[821] Matt. xii. 11; Mark iv. 11; Luke viii. 10.
[822] Ps. lxxviii. 2.
[823] Matt. xiii. 33.
[824] According to the conjecture of Sylburgius, σύντονος is
adopted for σύντομος.
[825] Empedocles.
[826] John i. 18.
[827] Acts xvii. 22, 23.
[828] Matt. xi. 27; Luke iii. 22.
[829] John viii. 24.
[830] John iii. 15, 16, 36, v. 24.
[831] Ps. ii. 12.
[832] The text ἐπίστηται, but the sense seems to require
ἐπίστευσε.
[833] πέποιθεν is confidence.
[834] John x. 1–3, 7.
[835] Eph. iii. 5.
[836] Joel ii. 28.
[837] Wisd. vii. 24.
[838] Ps. xxxvi. 5.
[839] Ps. civ. 4.
[840] Eusebius reads ποιητιχῶς.
[841] γενητόν.
[842] Gen. i. 1–3.
[843] Deut. xiii. 4.
[844] The text has πάλιν; Euseb. reads Πλάτων.
[845] The text has ἀνθρώπῳ; Plato and Eusebius, ἀνθρώπois.
[846] Deut. xxx. 15, 19, 20.
[847] τὴν χρυσῆν is supplied, according to a very probable
conjecture.
[848] “Spoken or” supplied from Plato and Eusebius.
[849] μόνον ἐν τῇ πόλει is here supplied from Plato.
[850] Iliad, xiv. 206.
[851] Iliad, xviii.
[852] Μέτρα is the reading of the text, but is plainly an error for
μέτρῳ, which is the reading of Eusebius.
[853] Eph. vi. 12.
[854] Ps. iii. 5.
[855] Matt. xxiv. 42, etc.
[856] Wisd. ii. 12.
[857] Isa. xl. 18, 25.
[858] H. Stephanus, in his Fragments of Bacchylides, reads
αἰκελείων (foul) instead of ἀεικαιλιαν of the text.
[859] Quoted in Exhortation to the Heathen, p. 72, and is here
corrected from the text there.
[860] This is quoted in Exhortation to the Heathen, p. 73, ch.
viii. The reading varies, and it has been variously amended. Θεῷ
is substituted above for σέο. Perhaps the simplest of the
emendations proposed on this passage is the change of σέο into
σο, with Thee.
[861] Heraclitus.
[862] Deut. vi. 4.
[863] See Exhortation, p. 76, where for “So” read “Lo.”
[864] “Οὖτις, Noman, Nobody; a fallacious name assumed by
Ulysses (with a primary allusion to μήτις, μῆτις, Odys. xx. 20), to
deceive Polyphemus.”—Liddel and Scott. The third line is 274 of
same book.
[865] Odys. ix. 410.
[866] Iliad, xxii. 8.
[867] Isa. xl. 18, 19.
[868] All these lines from Epicharmus: they have been
rendered as amended by Grotius.
[869] λόγος [or Word].
[870] Isa. i. 11, 16.
[871] This passage, with four more lines, is quoted by Justin
Martyr, De Monarchia, p. 335, and ascribed by him to Philemon.
[872] Jer. xxiii. 23, 24.
[873] Ps. iv. 6.
[874] In Justin Martyr, in the place above quoted, these lines
are joined to the preceding. They are also quoted by Eusebius,
but differently arranged. The translation adopts the arrangement
of Grotius.
[875] Isa. lxv. 24.
[876] These lines are quoted by Justin (De Monarchia), p. 333,
but ascribed by him part to Philemon, part to Euripides.
[877] Ascribed by Justin to Sophocles.
[878] Adopting the reading κεῖνος instead of καινός in the text.
[879] Quoted in Exhortation, p. 74.
[880] Isa. lxvi. 1.
[881] Isa. lx. 1, 2.
[882] Isa. xl. 12.
[883] Amos iv. 13.
[884] Deut. xxxii. 39.
[885] For οὐρανοὺς ὁρᾶς we read ἀνθρώπους (which is the
reading of Eusebius); and δρῆς (Sylburgius’ conjecture), also
from Eusebius, instead of ἃ θεμις ἀθέμιστα.
[886] Isa. x. 14.
[887] Jer. x. 12.
[888] Isa. xl. 13.
[889] Iliad, viii. 69.
[890] These lines of Æschylus are also quoted by Justin
Martyr, De Monarchia, p. 330. (Dread force, ἄπλατος ὁρμή;
Eusebius reads ὁρμῇ, dative. J. Langus has suggested
(ἄπλαστος) uncreated; ἄπληστος (insatiate) has also been
suggested.) The epithet of the text, which means primarily
unapproachable, then dread or terrible, is applied by Pindar to
fire.
[891] Ps. lxviii. 8.
[892] This Pythian oracle is given by Herodotus, and is quoted
also by Eusebius and Theodoret.
[893] γνωμικώτατα, Eusebius reads γενικώτατον, agreeing with
πατέρα.
[894] A game in which a potsherd with a black and white side
was cast on a line; and as the black or white turned up, one of the
players fled and the other pursued.
[895] Eusebius has κρίνει, which we have adopted, for κρίνειν
of the text.
[896] Plato, Rep. book vii.
[897] According to the reading in Eusebius, πᾶν ἔθνος ἑῷον,
πᾶν δὲ ἑσπερίων ᾐόνων, βόρειόν τε καὶ τό, κ.τ.λ.
[898] Instead of πρόνοιαν, Eusebius has προνομίαν (privilege).
[899] Clement seems to mean that they knew God only in a
roundabout and inaccurate way. The text has περίφασιν; but
περίφρασιν, which is in Eusebius, is preferable.
[900] Isa. xxxvi. 7, 8, 10.
[901] Jonah i. 6, 9, 14.
[902] Mal. i. 10, 11, 14.
[903] Perhaps Bacchylides.
[904] ἀρχαίαν.
[905] The reading of H. Stephanus, ἀγαθὰς Ὥρας, is adopted
in the translation. The text has ἀγαθὰ σωτῆρας. Some supply
Ὥρας, and at the same time retain σωτῆρας.
[906] Jer. iii. 19.
[907] John vi. 27.
[908] Isa. xxxii. 20.
[909] Rom. xiv. 2.
[910] Ps. cxii. 5, 9.
[911] Odyssey, xi. 420.
[912] Homer, Iliad, xxiii. 315: μέγ’ ἀμείνων is found in the Iliad
as in Musæus. In the text occurs instead περιγίνεται, which is
taken from line 318.
αὐτὰρ’ ὑπένερθεν,
Νίκης πείρατ’ ἔχοντα, ἐν ἀθανάτοισι θεοῖσιν.