Thousands. Books, tutorials, references.... Two, one local and one at random from web somewhere, are
Yes, of : "Von Neumann Languages": FORTRAN, BCPL, PL/I, Ada, Pascal, ...
Typical assignment in typical language: right hand side is
easily formalizable with mathematics and thus stands a chance of
meaningful semantical analysis (what it means, is it correct?).
A = f(g(a+h(b)+cv)+g(a))
But "Statements" hard to formalize:
for
while
switch
if ... elsif...
if ... then ... else
FORTRAN, BCPL, C... mirror the computer's instructions and
architecture --
thus easy to compile, efficient code, and paradigmatic of the
Von Neumann computer.
#include\#include #include #define w "Hk~HdA=Jk|Jk~LSyL[{M[wMcxNksNss:" #define r"Ht@H|@=HdJHtJHdYHtY:HtFHtF=JDBIl"\ "DJTEJDFIlMIlM:HdMHdM=I|KIlMJTOJDOIlWITY:8Y" #define S"IT@I\\@=HdHHtGH|KILJJDIJDH:H|KID"\ "K=HdQHtPH|TIDRJDRJDQ:JC?JK?=JDRJLRI|UItU:8T" #define _(i,j)L[i=2*T[j,O[i=O[j-R[j,T[i=2*\ R[j-5*T[j+4*O[j-L[j,R[i=3*T[j-R[j-3*O[j+L[j, #define t"IS?I\\@=HdGHtGIDJILIJDIItHJTFJDF:8J" #define y yy(4),yy(5), yy(6),yy(7) #define yy( i)R[i]=T[i],T[i ] =O[i],O[i]=L [i] #define Y _(0 ], 4] )_ (1 ], 5] )_ (2 ], 6] )_ (3 ], 7] )_=1 #define v(i)( (( R[ i ] * _ + T [ i ]) * _ + O [ i ]) * _ + L [ i ]) *2 double b = 32 ,l ,k ,o ,B ,_ ; int Q , s , V , R [8 ], T[ 8] ,O [8 ], L[ 8] ; #define q( Q,R ) R= *X ++ % 64 *8 ,R |= *X /8 &7 ,Q=*X++%8,Q=Q*64+*X++%64-256, # define p "G\\QG\\P=GLPGTPGdMGdNGtOGlOG" "dSGdRGDPGLPG\\LG\\LHtGHtH:" # define W "Hs?H{?=HdGH|FI\\II\\GJlHJ" "lFL\\DLTCMlAM\\@Ns}Nk|:8G" # define U "EDGEDH=EtCElDH{~H|AJk}" "Jk?LSzL[|M[wMcxNksNst:" # define u "Hs?H|@=HdFHtEI" "\\HI\\FJLHJTD:8H" char * x ,*X , ( * i )[ 640],z[3]="4_", *Z = "4,8O4.8O4G" r U "4M"u S"4R"u t"4S8CHdDH|E=HtAIDAIt@IlAJTCJDCIlKI\\K:8K"U "4TDdWDdW=D\\UD\\VF\\FFdHGtCGtEIDBIDDIlBIdDJT@JLC:8D"t"4UGDNG\\L=GDJGLKHL\ FHLGHtEHtE:"p"4ZFDTFLT=G|EGlHITBH|DIlDIdE:HtMH|M=JDBJLDKLAKDALDFKtFKdMK\ \\LJTOJ\\NJTMJTM:8M4aGtFGlG=G|HG|H:G\\IG\\J=G|IG|I:GdKGlL=G|JG|J:4b"W S"4d"W t t"4g"r w"4iGlIGlK=G|JG|J:4kHl@Ht@=HdDHtCHdPH|P:HdDHdD=It\ BIlDJTEJDFIdNI\\N:8N"w"4lID@IL@=HlIH|FHlPH|NHt^H|^:H|MH|N=J\\D\ J\\GK\\OKTOKDXJtXItZI|YIlWI|V:8^4mHLGH\\G=HLVH\\V:4n" u t t "4p"W"IT@I\\@=HdHHtGIDKILIJLGJLG:JK?JK?=JDGJLGI|MJDL:8M4\ rHt@H|@=HtDH|BJdLJTH:ITEI\\E=ILPILNNtCNlB:8N4t"W t"4u" p"4zI[?Il@=HlHH|HIDLILIJDII|HKDAJ|A:JtCJtC=JdLJtJL\ THLdFNk|Nc|\ :8K"; main ( int C,char** A) {for(x=A[1],i=calloc(strlen(x)+2,163840); C-1;C<3?Q=_= 0,(z[1]=*x++)?((*x++==104?z[1]^=32:--x), X = strstr(Z,z)) &&(X+=C++):(printf("P2 %d 320 4 ",V=b/2+32), V*=2,s=Q=0,C =4):C<4?Q-->0?i[(int)((l+=o)+b)][(int)(k+=B) ]=1:_?_-=.5/ 256,o=(v(2)-(l=v(0)))/(Q=16),B=(v(3)-(k=v(1) ))/Q:*X>60?y ,q(L[4],L[5])q(L[6],L[7])*X-61||(++X,y,y,y), Y:*X>57?++X, y,Y:*X >54?++X,b+=*X++%64*4:--C:printf("%d " ,i[Q][s]+i[Q ][s+1]+i[Q+1][s]+i[Q+1][s+1])&&(Q+=2)&V||(Q= 0,s+=2)<640 ||(C=1));}
Obfuscated C Code Contest winners
This program takes a single command line argument, transcribes the argument text into Tolkien's Elvish letters, and writes the transcription to standard output as a portable graymap (PGM) file.
The specific transcription mode is the Black Speech Tengwar mode, as used in the inscription on the One Ring. The program handles the following diagraphs:
- "gh", "sh", "th": the corresponding tengwar are output for these specific sounds - "mh" denotes the full tengwa for [m]; "m" by itself means a horizontal bar above the next letter - "rh" denotes the [r\] tengwa - "uh" denotes the tehta for long vowel [u:] - "zh" selects the up-reaching tengwa for [z], while "z" selects the down-reaching one
Punctuation marks other than commas and periods are ignored, as are whitespace characters. In addition, the argument text must be entirely in lower case.
The following command thus writes a rendering of the Ring inscription to
the file out.pgm:
./anonymous "ash nazg durhbatuluhk,
ash nazg gimbatul,
ash nazg thrakatuluhk,
agh burzhumh-ishi krimpatul."
>out.pgm
Very close to machine-code level. E.g. constructing pointers to anywhere.
By Java standards, few declarations and less type checking. Fewer ``built in'' standard libraries.
Lots of legacy code around.
Possible to construct object-oriented code, modular programming style (e.g. Quake II game engine).
Besides a few idiosyncrasies, a good representative imperative language, used in lots of future CSC courses.
E.g. Matlab language is very like C with huge built-in libraries of specialized functions. (Matlab has structures and some inheritance pasted on, but very limited use of pointers (aka handles)).
#include <stdio.h>
main(int arg, char *argv[])
{ if (argc == 2)
printf("Hello %s\n",argv[1]);
}
Class Hello {
public static void main (String args[]}
{
if (args.length == 1) {
System_out print ("Hello");
System_out println (args[0]);
}}
int main (int argc, char *argv[])
{ ...}
Top-level program always called main. Lots of separate files used and needed for big programs. Hence make.
storage classes (with separate compilation of files)
(global) static
(local) static
extern
const, hence
#include
--- typedefs and externs in .h file
--- matching globals in *one* .c file each
I/O
#include <stdio.h>
printf, scanf, puts, gets, putchar, getchar
FILE *fopen (const char* filename, const char *mode)
fprintf, fscanf, fputs, fgets, fputc,
fputc, fwrite, fread, sprintf, sscanf
Data Types, Control, Arithmetic, Conditionals, Functions, Structures, Strings, Bit Operations, I/O -- all bog-standard.
Scope: Global, Static (to file) , Automatic (Local to function).
Makefile: organize the compiling and linking given edits and changes. (make, gmake?). General tool for stating dependencies and how to resolve them. Latex, your experiments...whatever. Like Prolog??
Character Strings: strings.h library, ended by null character \0.
Type Conversion...via cast or "what you expect". Not as pernicious as Matlab's, much looser than Java!
Preprocessor, #include, and .h files.
Needed because even simplest I/O or
mathematical functions need their own libraries (!)
#include <stdio.h>
#include <math.h>
I/O: stdin, stdout, stderr, getchar, putchar, scanf, printf, fopen, getc, putc, fclose, feof, fscanf, fprintf, sscanf, sprintf. Matlab's are a subset, work similarly but not exactly.
Memory Management (calloc, malloc)
Command Line Arguments -- as in Java
No boolean type: use ints or null pointer.
Structs are like classes without methods, and with all-public fields
declaration syntax:
--- read right as far as possible, then left,
--- then out one level of parentheses (if any) and repeat.
Egs:
struct foo *bar[10];
bar is 10-elt arr of ptrs to foo structs
const char *s;
s is ptr to chars that are constant, but
char * const t;
t is a constant pointer to chars
typedef: gives names to struct definitions
Very Useful with the "enumerated" data type operator
enum :
typedef enum {UP, DOWN, LEFT, RIGHT} direction;
C has in-line allocation of structured objects (structs). A pointer is an address, and to "dereference" the pointer is to retrieve what is at that address. Very common in C programs.
In Java. non-basic types (i.e. all classes and all arrays) dynamically allocated. A variable of a non-basic type is a *reference* to the dynamically-allocated space: recursive types natural:
class listnode {
mytype data;
listnode next;
}
In C all types (including structs and arrays) are allocated in
place by default. Recursive types don't make sense. Use
explicit POINTER type:
struct listnode {
mytype data;
struct listnode * next;
}
struct node {
int datum;
struct node *next;
}
node *find (int d, node *head) {
while (head) {
if (head->datum == d)
/* or ((*head).datum == d) not 'X = d'! */
return head;
head = head->next;
}
return 0;
}
Use calloc or malloc, sizeof, free.
calloc, malloc are very similar:
void free;
void *malloc(); /* also calloc() */
int *foo = (int *) malloc
(10 * sizeof (int));
...
free (foo);}
/* 'memory leak' otherwise */
Allocate space for 1000 ints.
#include < stdlib.h >
int * MyKintsPtr;
MyKintsPtr = (int *)
calloc(sizeof(int), 1000);
/* memory contents zeroed by calloc */
MyKintsPtr = (int *)
malloc(1000*sizeof(int));
/* (whoever's) old memory contents preserved */
/* we lost pointer to first 1000-long array! */
free(MyKintsPtr);
/*no help, still a memory leak*/
File manipulation, utilities ( awk, sed, yacc, lex, grep ), pipes (|), I/O redirection (>, <, etc.), shell and shell scripts.
See the Primary Readings, Books at Carlson Reserve, etc. cd, cat,
ls,
mv, cp,
mkdir, chmod, less, file redirection (>,<,>>,...),
ssh,
``dot'' files: list with ls -a :
.cshrc
.login
.cshrc
.emacs
Job control, command-line edits, grep, rcs (ci,co, rcs, rlog), enscript, psnup, whatever.
EMACS: See Primary Readings, many books, on-line tutorial, info mode of emacs...
gdb (read the emacs info page!):
list;
break, watch;
run, cont, next;
where;
print, display;
whatis;
ptype ...
Here's a little GDB example session .
MAKE:
Small examples will follow. See Primary Readings for extended
example and things to look for. Also the
emacs info page has info on make. Here's something for example...
U. Md. make Tutorial.
At a hardware level, "indirect address" instructions ARE pointer instructions.
Variable: a memory location containing a numerical value.
Pointer: a memory location that contains an address.
Address Operator &
applies to a variable, returns address of that variable:
ptr_v = &x;
Indirection Operator * applies to pointer, retrieves value from memory
location held in that pointer (i.e. retrieves what the
pointer ``points to'').
*ptr_v = 699;
scanf for input
can't affect its arguments outside, so must use pointers.
scanf("%d %d", &r, &c);
/* more basic egs: */
short x = 33;
short *sptr;
sptr = & x;
*sptr = -123;
Must declare pointer and the type of its variable!
double *dptr;
double* d2ptr;
char *malloc();
C is strictly call by value, so this does NOT work!
void Swap_it(int u,v);
{
int temp;
temp = u;
u = v;
v = temp;
}
So we implement call-by-reference
like this:
/* this takes values of addresses in, swaps
what's IN those address values*/
void SwapByRef(int *u, int *v);
/*take THIS, Call By Value! */
{ int temp;
temp = *v; *v = *u, *u = temp;
}
main()
{ int x=10, y = 2;
SwapByRef(&x, &y);
}
/* VARIABLE DEFINITIONS (global or local)
(these allocate space):*/
int foo[100]; /* 100-elt arr of ints */
int *foo; /* ptr to int (or elt of int arr) */}
/* code: */
foo[10]
above works with EITHER variable definition:
correct with latter only if foo refers to
an array with at least 11 elements
(indices start at zero, as in Java).
PARAM DECLARATIONS (in function prototype [header])
(these do NOT allocate space):
int foo[100] /* ptr to 100-elt int array */
int foo[] /* size irrelevant */
int *foo /* same as above*/
Declarations of extern arrays allow
missing sizes, as in parameter declarations.
2D v. row-pointer array layout:
/* variable definitions:*/
int foo[10][10];
/* 10x10 arr of ints, contig. layout */
int *foo[10];
/* 10-elt arr of ptrs to ints.
a DIFFERENT LAYOUT, more like Java */
/* code: */
foo[3][4] /* works with EITHER definition */
parameter declarations:
int foo[10][10]
/* 10x10 arr of contig. ints*/
int foo[][10]
/* first dimension size irrelevant */
int foo[10][]
/* ERROR: must know size of 2nd dim. */
int *foo[10]
/* row-pointer layout */
int *foo[]
/* don't have to know size*/
int **foo
/* same as above */
Political Incorrectness: we know array indexing implemented with
pointer arithmetic. So....
*(mat + i) = 123;
is (basically) same as
mat[i] = 123;.
Here invisible type-conversion is maybe needed, don't know if it
happens. If i is compiled meaning "integer" and it's an array
of "bytes" then....:-}. Thus not a great style. Matlab has similar
problems with "too much information" instead of "information hiding".
Declaring an array implicitly declares pointer to its zeroth element: the array name itself!
So C passes arrays to functions by reference:
int MyArr[MAX];
SortArr(MyArr, MAX);
could return sorted array in MyArr, whereas we know
we can't affect integer arguments outside!
/* declare a struct */
struct date {
int month;
int day;
int year;
};
struct date today;
/* create a struct named today
AT COMPILE TIME*/
today.day = 21;
/* update a field */
As usual, structures of arrays and vice versa, structures within structures, etc. all as expected. Usually want pointer to struct, not its name as above, since they may not have names, it's boring to declare 100 structs, and we often have a data structure full of anonymous structs that point at each other.
struct date *date_pointer;
/*assign it to some date struct, then */
(*date_pointer).day =21;
/* correct syntax, but yikes!*/
date_pointer -> day = 21;
/* so... nicer syntax */
In the bad old days, you had to write your own matrix package!
This is part of mine...
The typedef statement lets us create a new type-name for
pointer to our struct.
typedef struct matrix {
int r; /* rows*/
int c; /* cols */
dmat mat; /* rows*cols numbers */
} *matrix_t;
/*here's the new pointer type*/
/* Matrix Addition Function: Return +-
sum of 2 args */
/* Olllld Syntax! (lurking in CB's code)*/
matrix_t mat_add(a,b,sign); /* args*/
matrix_t a,b; double sign; /* their types*/
/* ANSI Syntax */
matrix_t mat_add
(matrix_t a, matrix_t b, double sign);
{
int i,j; matrix_t sum;
if ((a->r != b->r) || (a->c != b->c)) {
{
cberror("mat_add: bad sizes");
return (NULL);}
sum = mat_new(a->r, a->c);
if (sum ==NULL) { cberror("mat_add: memory?");
return NULL;}
for (i=0; i = a->r; i++)
/* ++ increments by 1: very C-ish */
for (j=0; j = a->c; j++)
sum->mat[i][j]=
a->mat[i][j]+sign* b->mat[i][j];
/* don't need {} around
single-statement for-loops. */
return sum;
}
int get_character(location_t *loc)
{
int rtn;
if (loc->column >= loc->line->length) {
return 0;
}
rtn = loc->line->data[loc->column++];
if (loc->column >= loc->line->length
&& loc->line->next) {
loc->line = loc->line->next;
loc->column = 0;
}
return rtn;
...
m = mat_new(int r, int c);
/* m points to new struct with
rows, cols filled in, no data */
for (i=0; i<r; i++)
{
for (j=0; j<c; j++)
scanf("%lf",&((m->mat)[i][j]));
/*fills up data matrix of struct*/
}
return m; /* or use it... */
Some is automagic: e.g. arith. ops with floats and ints
Explicit casting: average = (float) total / n;
Casts are rather common:
a =(matrix_t)
malloc ((unsigned) sizeof(struct matrix))
It's obvious what we want done with most files --an executable file implies we have to compile and link source files, C files want a C compiler, etc.. There are highly-evolved conventions, defaults, shorthand, etc. exist. Not below.
targets (actions to be completed) on left before colons. TABS
are part of syntax!! that's not just white space.
What the target needs done to make it is on the right. So
make(clean) at top level removes all the object files.
OBJS = scanit.o char_classes.o
INCS = char_classes.h scanit.h
FLAGS = -g
runtest: $(OBJS)
gcc -o runtest $(FLAGS) $(OBJS)
scanit.o: scanit.c $(INCS)
gcc -c scanit.c
clean:
rm *.o
That backslash is the makefile line-continuation operator...
line breaks and tabs aren't just whitespace.
LIBS = -lm
### compiler control ###
CFLAGS = -g
CC = gcc
#-------------------------------------------------
track: lattice.o driver.o
${CC} ${CFLAGS} lattice.o driver.o \
${LIBS} -o pred
lattice.o: lattice.c
driver.o: driver.c
Disclaimer: most of this code sort of worked sometime. Normal C compiler nowadays is "gnu C". ANSI C is pretty portable, but typos, bugs, etc. always exist! Also they are written by CB, probably the absolute last programming stylist a sane person would ever consult. Take these for what they're worth.
#include < stdio.h >
#include < math.h > /*libraries*/
#include "cbtypes.h"
#include "cbmath.h" /*yours*/
double Contaminated_Normal();
/* returns a double */
main()
{
int i,j, rseed;
double p,m2,s2,m,s,n;
set_seed();
/*initializes a random generator*/
for(j=0; j<3; j++)
{
printf("\np, mean1, std1, m2, std2:");
scanf("%lf %lf %lf %lf %lf",
&p, &m, &s, &m2, &s2);
for (i = 0; i<20; i++)
{ n = Contaminated_Normal(p,m,s,m2,s2);
printf("\n variate: %f ", n);
}}}
#include < stdio.h >
#include < sys/time.h >
#include < math.h >
#define SAMPLE_SIZE 2147483647
/* range of random generator */
#define ROOT12 3.4641016151377544
long random(); /* library function */
char *malloc();
/* do. common, still must declare */
double N();
/* Contaminated_Normal:
for fraction p of time
it is normal of (m1,std1).
(1-p) of the time it is normal
of (m2, std2) */
/*here we go -- Finally...*/
double Contaminated_Normal
(p,m1, std1, m2, std2)
double m1,m2, p, std1, std2;
{
double fac,u1, u2, v1, v2, s;
long u;
static int iset = 0;
static double gset;
u = random();
u1 =
((double) u ) / SAMPLE_SIZE; /*cast!*/
if (u1 <= p) return N(m1,std1);
else return N(m2, std2);
}
#define /*more macros...*/
#include
/* for conditional compilation, say...*/
#ifdef, #endif, #else, #ifndef
#if, #elif
/* defining some useful matrix
data structures, routines...
/*
#include < stdio.h >
#include < math.h >
#include "cbtypes.h"
#include "cbmath.h"
/* we'll see this next*/
/* externally-defined names redeclared */
char *malloc(); /* lest we forget */
void cberror(msg);
/* here we go...*/
char msg[];
{
void exit();
fprintf(stderr,
"\nError: %s, old buddy.", msg);
}
/***simplified versions
with ranges [0,N-1] **/
/*Vectors are columns*/
ivec ivector(n)
int n;
{
return (ivec)
malloc((unsigned) n*sizeof(int));
}
...
#ifndef _cbmath_h
#define _cbmath_h
/* common C-ism:
define unlikely-named variable
the first time this file is processed:
after first time,
other mentions are ignored */
/*****important matrix macro--
saves lots of typing *****/
#define e(m,i,j) m->mat[i][j]
/******some basic macros ********/
#define max(x,y) x>y?x:y
#define min(x,y) x>y?y:x
/* #define abs(x) x>0?x:-x */
#define deg_to_rad ( (double) M_PI/180.0)
/*external matrix stuff defined elsewhere*/
extern void cberror();
extern int lubksb();
extern int lubcmp();
extern void ivec_free();
extern void mat_free();
/*****error codes*****/
#define OK 1
#define MALLOC 0
/****general matrix types ****/
typedef double *dvec;
typedef int *ivec;
typedef double **dmat;
typedef struct matrix {
int r;
int c;
dmat mat;
} *matrix_t;
Unlike polymorphic Java, we would need
diff. functions for ints, doubles....!!
Also, if declare, say double M[4][4] then need 4x4 matrix ops.
What about 1x4 or 5x5?? :-{.
We do this:
dvec dvector(n) int n; { return (dvec) malloc((unsigned) n*sizeof(double)); } /* create matrix by allocating r c-long vectors for the rows, a vector of pointers to rows, and a pointer to the latter vector. */ matrix_t mat_new(int r,int c) /*r rows, c cols*/ { int i; dmat m; matrix_t a; m = (dmat) malloc( r*sizeof(double *)); if (m == NULL) return NULL; for (i= 0; i < r; i++) { m[i] = (dvec) malloc( c*sizeof(double)); if (m[i] == NULL) return NULL; } a =(matrix_t) malloc ( sizeof(struct matrix)); if ( a == NULL) return NULL; a->r = r; a->c = c; a->mat = m; a-> fev_type = MATRIX; return a; } /* can't just free the pointer to the matrix, there's no garbage collection */ void mat_free(m) matrix_t m; { int i,r; r =m->r; for (i = 0; i < r; i++) free ((char *) m->mat[i]); free((char *) m->mat); free((char *) m); }
Definition of main:
int main (int argc, char *argv[])}
So argv is an array that contains elements that are ``pointer to
char''s, or strings. When main is called, the first arg gets
assigned the number of args on command line. The second 'argument
vector' has argc+1 entries, with [0] being a pointer to the
name of the program executing, and the rest are pointers to the
strings on the command line. So can check on number of args, if wrong
or an error (say no file by a requested name), print message and
``how to invoke'' help...
e.g. on command line at top-level:
CopyFile FromFile ToFile