提交 8c592517 编写于 作者: B Ben

Copy the code from the previous repo

上级 2d45308c
21st-Century-Examples
=====================
[ Until I actually populate this repository, get the examples from http://examples.oreilly.com/0636920025108/ .]
Dear Reader,
Here are all of the examples from _21st Century C_ by Ben Klemens [ http://tinyurl.com/C-for-moderns ]. You'll notice that the captions for all of the examples in the text end in a filename in parens, like (string_utilities.c); that name is referring to the file here.
......
/* See compilation notes in amort_use.c*/
#include "stopif.h"
#include <stdio.h>
#include "amortize.h"
amortization_s amortize_prep(amortization_s in){
Stopif(!in.amount || in.amount < 0 || in.rate < 0
|| in.months < 0 || in.years < 0 || in.selloff_month < 0 || in.selloff_year < 0,
return (amortization_s){.error="Invalid input"},
"Invalid input. Returning zeros.");
int months = in.months;
if (!months){
if (in.years) months = in.years * 12;
else months = 12 * 30; //home loan
}
int selloff_month = in.selloff_month;
if (!selloff_month && in.selloff_year)
selloff_month = in.selloff_year * 12;
amortization_s out = in;
out.rate = in.rate ? in.rate : 4.5;
out.interest = amortize(in.amount, out.rate, in.inflation,
months, selloff_month, in.extra_payoff, in.show_table,
&(out.interest_pv), &(out.years_to_payoff), &(out.monthly_payment));
return out;
}
/* Suggested makefile:
----------
P=amort_use
objects=amort_interface.o amortize.o
LDLIBS=-lm
CFLAGS=-g -Wall -O3 -std=gnu11 #the usual
$(P):$(objects)
----------
*/
#include <stdio.h>
#include "amortize.h"
int main(){
printf("A typical loan:\n");
amortization_s nopayments = amortization(.amount=200000, .inflation=3);
printf("You flushed real $%g down the toilet, or $%g in present value.\n",
nopayments.interest, nopayments.interest_pv);
amortization_s a_hundred = amortization(.amount=200000, .inflation=3,
.show_table=0, .extra_payoff=100);
printf("Paying an extra $100/month, you lose only $%g (PV), "
"and the loan is paid off in %g years.\n",
a_hundred.interest_pv, a_hundred.years_to_payoff);
printf("If you sell off in ten years, you pay $%g in interest (PV).\n",
amortization(.amount=200000, .inflation=3,
.show_table=0, .selloff_year=10).interest_pv);
}
/* See compilation notes in amort_use.c*/
#include <math.h> //pow.
#include <stdio.h>
#include "amortize.h"
double amortize(double amt, double rate, double inflation, int months,
int selloff_month, double extra_payoff, int verbose,
double *interest_pv, double *duration, double *monthly_payment){
double total_interest = 0;
*interest_pv = 0;
double mrate = rate/1200;
//The monthly rate is fixed, but the proportion going to interest changes.
*monthly_payment = amt * mrate/(1-pow(1+mrate, -months))+extra_payoff;
if (verbose) printf("Your total monthly payment: %g\n\n", *monthly_payment);
int end_month = (selloff_month && selloff_month < months )
? selloff_month
: months;
if (verbose) printf("yr/mon\t Princ.\t\tInt.\t| PV Princ.\t PV Int.\t Ratio\n");
int m;
for (m=0; m < end_month && amt > 0; m++){
double interest_payment = amt*mrate;
double principal_payment = *monthly_payment - interest_payment;
if (amt <= 0)
principal_payment =
interest_payment = 0;
amt -= principal_payment;
double deflator = pow(1+ inflation/100, -m/12.);
*interest_pv += interest_payment * deflator;
total_interest += interest_payment;
if (verbose) printf("%i/%i\t%7.2f\t\t%7.2f\t| %7.2f\t %7.2f\t%7.2f\n",
m/12, m-12*(m/12)+1, principal_payment, interest_payment,
principal_payment*deflator, interest_payment*deflator,
principal_payment/(principal_payment+interest_payment)*100);
}
*duration = m/12.;
return total_interest;
}
/* See compilation notes in amort_use.c*/
double amortize(double amt, double rate, double inflation, int months,
int selloff_month, double extra_payoff, int verbose,
double *interest_pv, double *duration, double *monthly_payment);
typedef struct {
double amount, years, rate, selloff_year, extra_payoff, inflation;
int months, selloff_month;
_Bool show_table;
double interest, interest_pv, monthly_payment, years_to_payoff;
char *error;
} amortization_s;
/**
Calculate the inflation-adjusted amount of interest you would pay
over the life of an amortized loan, such as a mortgage.
\li \c amount The dollar value of the loan. No default--if unspecified,
I print an error and return zeros.
\li \c months The number of months in the loan. Default: zero, but see years.
\li \c years If you do not specify months, you can specify the number of
years. E.g., 10.5=ten years, six months.
Default: 30 (a typical U.S. mortgage).
\li \c rate The interest rate of the loan, expressed in annual
percentage rate (APR). Default: 4.5 (i.e., 4.5%), which
is typical for the current (US 2012) housing market.
\li \c inflation The inflation rate as an annual percent, for calculating
the present value of money. Default: 0, meaning no
present-value adjustment. A rate of about 3 has been typical
for the last few decades in the USA.
\li \c selloff_month At this month, the loan is paid off (e.g., you resell
the house). Default: zero (meaning no selloff).
\li \c selloff_year If selloff_month==0 and this is positive, the year of
selloff. Default: zero (meaning no selloff).
\li \c extra_payoff Additional monthly principal payment. Default: zero.
\li \c show_table If nonzero, display a table of payments. If zero, display
nothing (just return the total interest). Default: 1
All inputs but \c extra_payoff and \c inflation must be nonnegative.
\return an \c amortization_s structure, with all of the above values set as
per your input, plus:
\li \c interest Total cash paid in interest.
\li \c interest_pv Total interest paid, with present-value adjustment for inflation.
\li \c monthly_payment The fixed monthly payment (for a mortgage, taxes and
interest get added to this)
\li \c years_to_payoff Normally the duration or selloff date, but if you make early
payments, the loan is paid off sooner.
\li error If <tt>error != NULL</tt>, something went wrong and the results are invalid.
*/
#define amortization(...) amortize_prep((amortization_s){.show_table=1, \
__VA_ARGS__})
amortization_s amortize_prep(amortization_s in);
/* Compile with:
make arithmetic CFLAGS="-g -Wall -std=gnu11 -O3"
*/
#include <stdio.h>
int main(){
int evens[5] = {0, 2, 4, 6, 8};
printf("The first even number is, of course, %i\n", *evens);
int *positive_evens = &evens[1];
printf("The first positive even number is %i\n", positive_evens[0]);
}
if [ -e autodemo ]; then rm -r autodemo; fi
mkdir -p autodemo
cd autodemo
cat > hello.c <<\
"--------------"
#include <stdio.h>
int main(){ printf("Hi.\n"); }
--------------
cat > Makefile.am <<\
"--------------"
bin_PROGRAMS=hello
hello_SOURCES=hello.c
--------------
autoscan
sed -e 's/FULL-PACKAGE-NAME/hello/' \
-e 's/VERSION/1/' \
-e 's|BUG-REPORT-ADDRESS|/dev/null|' \
-e '10i\
AM_INIT_AUTOMAKE' \
< configure.scan > configure.ac
touch NEWS README AUTHORS ChangeLog
autoreconf -iv
./configure
make distcheck
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make automem
*/
#include <stdio.h>
typedef struct powers {
double base, square, cube;
} powers;
powers get_power(double in){
powers out = {.base = in,
.square = in*in,
.cube = in*in*in};
return out;
}
int *get_even(int count){
int out[count];
for (int i=0; i< count; i++)
out[i] = 2*i;
return out; //bad.
}
int main(){
powers threes = get_power(3);
int *evens = get_even(3);
printf("threes: %g\t%g\t%g\n", threes.base, threes.square, threes.cube);
printf("evens: %i\t%i\t%i\n", evens[0], evens[1], evens[2]);
}
for i in 0 1 2 3 4 5 6 7 8 9; do grep -E '(^|[^0-9.])'$i *.c > lines_with_${i}; done
wc -l lines_with*
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make boxes
*/
#include <stdio.h>
typedef struct {
char *name;
int left, right, up, down;
} direction_s;
void this_row(direction_s d); //these functions are below
void draw_box(direction_s d);
int main(){
direction_s D = {.name="left", .left=1};
draw_box(D);
D = (direction_s) {"upper right", .up=1, .right=1};
draw_box(D);
draw_box((direction_s){});
}
void this_row(direction_s d){
printf( d.left ? "*..\n"
: d.right ? "..*\n"
: ".*.\n");
}
void draw_box(direction_s d){
printf("%s:\n", (d.name ? d.name : "a box"));
d.up ? this_row(d) : printf("...\n");
(!d.up && !d.down) ? this_row(d) : printf("...\n");
d.down ? this_row(d) : printf("...\n");
printf("\n");
}
/* Suggested makefile:
----------
P=cetology
CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3
LDLIBS=`pkg-config --libs glib-2.0`
objects=fstr.o string_utilities.o
$(P): $(objects)
----------
*/
#include "fstr.h"
int main(){
fstr_s *fstr = fstr_new("moby");
fstr_list chapters = fstr_split(fstr, "\nCHAPTER");
for (int i=0; i< chapters.count; i++){
fstr_list for_the_title=fstr_split(chapters.strings[i],"\\.");
fstr_show(for_the_title.strings[1]);
fstr_list me = fstr_split(chapters.strings[i], "\\WI\\W");
fstr_list whales = fstr_split(chapters.strings[i], "whale(s|)");
fstr_list words = fstr_split(chapters.strings[i], "\\W");
printf("\nch %i, words: %i.\t Is: %i\twhales: %i\n", i, words.count-1,
me.count-1, whales.count-1);
fstr_list_free(for_the_title);
fstr_list_free(me);
fstr_list_free(whales);
fstr_list_free(words);
}
fstr_list_free(chapters);
fstr_free(fstr);
}
P=cetology
CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3
LDLIBS=`pkg-config --libs glib-2.0`
objects=fstr.o string_utilities.o
$(P): $(objects)
/* Suggested makefile:
----------
P=charct
objects=string_utilities.o process_dir.o unictr.o
CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu11 -O3
LDLIBS=`pkg-config --libs glib-2.0`
$(P): $(objects)
----------
*/
#define _GNU_SOURCE //get stdio.h to define asprintf
#include "string_utilities.h" //string_from_file
#include "process_dir.h"
#include "unictr.h"
#include <glib.h>
#include <stdlib.h> //free
void hash_a_file(filestruct path){
GHashTable *hash = path.data;
char *sf = string_from_file(path.fullname);
if (!sf) return;
char *sf_copy = sf;
if (g_utf8_validate(sf, -1, NULL)){
for (gunichar uc; (uc = g_utf8_get_char(sf))!='\0';
sf = g_utf8_next_char(sf))
hash_a_character(uc, hash);
}
free(sf_copy);
}
int main(int argc, char **argv){
GHashTable *hash;
hash = new_unicode_counting_hash();
char *start=NULL;
if (argc>1) asprintf(&start, "%s", argv[1]);
printf("Hashing %s\n", start ? start: "the current directory");
process_dir(.name=start, .file_action=hash_a_file, .data=hash);
g_hash_table_foreach(hash, printone, NULL);
}
/* See compilation notes in simple_cplx.c*/
#include "cplx.h" //gsl_cplx_from_c99; see below.
#include <gsl/gsl_blas.h> //gsl_blas_ddot
#include <gsl/gsl_complex_math.h> //gsl_complex_mul(_real)
gsl_vector_complex *cvec_dot_gslcplx(gsl_vector_complex *v, gsl_complex x){
gsl_vector_complex *out = gsl_vector_complex_alloc(v->size);
for (int i=0; i< v->size; i++)
gsl_vector_complex_set(out, i,
gsl_complex_mul(x, gsl_vector_complex_get(v, i)));
return out;
}
gsl_vector_complex *vec_dot_gslcplx(gsl_vector *v, gsl_complex x){
gsl_vector_complex *out = gsl_vector_complex_alloc(v->size);
for (int i=0; i< v->size; i++)
gsl_vector_complex_set(out, i,
gsl_complex_mul_real(x, gsl_vector_get(v, i)));
return out;
}
gsl_vector_complex *cvec_dot_c(gsl_vector_complex *v, complex double x){
return cvec_dot_gslcplx(v, gsl_cplx_from_c99(x));
}
gsl_vector_complex *vec_dot_c(gsl_vector *v, complex double x){
return vec_dot_gslcplx(v, gsl_cplx_from_c99(x));
}
complex double ddot (complex double x, complex double y){return x*y;}
void gsl_vector_complex_print(gsl_vector_complex *v){
for (int i=0; i< v->size; i++) {
gsl_complex x = gsl_vector_complex_get(v, i);
printf("%4g+%4gi%c", GSL_REAL(x), GSL_IMAG(x), i < v->size-1 ? '\t' : '\n');
}
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make const
*/
#include <stdio.h>
int main(){
int *var;
int const **constptr = &var; // the line that sets up the failure
int const fixed = 20;
*constptr = &fixed; // 100% valid
*var = 30;
printf("x=%i y=%i\n", fixed, *var);
}
/* Compile with:
CFLAGS="-g -Wall" CC=c99 make constchange
*/
void set_elmt(int *a, int const *b){
a[0] = 3;
}
int main(){
int a[10] = {};
int const *b = a;
set_elmt(a, b);
}
/* Compile with:
export CFLAGS="-g -std=gnu11 -O3" #The usual, but without -Wall
make constfusion #Still, this will throw a warning
*/
#include <stdio.h>
int main(){
int *var;
int const **constptr = &var; // the line that sets up the failure
int const fixed = 20;
*constptr = &fixed; // 100% valid
*var = 30;
printf("x=%i y=%i\n", fixed, *var);
}
/* Compile with:
export CFLAGS="-g -Wall -O3" #the usual.
export CC=c99
make conststruct
*/
#include <assert.h>
#include <stdlib.h>
typedef struct {
int *counter1, *counter2;
} counter_s;
void check_counter(int *ctr){ assert(*ctr !=0); }
double ratio(counter_s const *in){
check_counter(in->counter2);
return *in->counter1/(*in->counter2+0.0);
}
int main(){
counter_s cc = {.counter1=malloc(sizeof(int)),
.counter2=malloc(sizeof(int))};
*cc.counter1 = *cc.counter2 = 1;
ratio(&cc);
}
/* Compile with:
make copystructs CFLAGS="-g -Wall -O3 -std=gnu99"
*/
#include <assert.h>
typedef struct{
int a, b;
double c, d;
int *efg;
} demo_s;
int main(){
demo_s d1 = {.b=1, .c=2, .d=3, .efg=(int[]){4,5,6}};
demo_s d2 = d1;
d1.b=14;
d1.c=41;
d1.efg[0]=7;
assert(d2.a==0);
assert(d2.b==1);
assert(d2.c==2);
assert(d2.d==3);
assert(d2.efg[0]==7);
}
/* Compile with:
make copystructs2 CFLAGS="-g -Wall -O3 -std=gnu99"
*/
#include <assert.h>
int main(){
int abc[] = {0, 1, 2};
int *copy = abc;
copy[0] = 3;
assert(abc[0]==3);
}
/* See compilation notes in simple_cplx.c*/
#include <complex.h> //nice names for C's complex types
#include <gsl/gsl_vector.h> //gsl_vector_complex
gsl_vector_complex *cvec_dot_gslcplx(gsl_vector_complex *v, gsl_complex x);
gsl_vector_complex *vec_dot_gslcplx(gsl_vector *v, gsl_complex x);
gsl_vector_complex *cvec_dot_c(gsl_vector_complex *v, complex double x);
gsl_vector_complex *vec_dot_c(gsl_vector *v, complex double x);
void gsl_vector_complex_print(gsl_vector_complex *v);
#define gsl_cplx_from_c99(x) (gsl_complex){.dat= {creal(x), cimag(x)}}
complex double ddot (complex double x, complex double y);
#define dot(x,y) _Generic((x), \
gsl_vector*: dot_given_vec(y), \
gsl_vector_complex*: dot_given_cplx_vec(y), \
default: ddot)((x),(y))
#define dot_given_vec(y) _Generic((y), \
gsl_complex: vec_dot_gslcplx, \
default: vec_dot_c)
#define dot_given_cplx_vec(y) _Generic((y), \
gsl_complex: cvec_dot_gslcplx, \
default: cvec_dot_c)
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make curly
*/
#include <stdio.h>
#define sum(max, out) { \
int total=0; \
for (int i=0; i<= max; i++){ \
total += i; \
} \
out = total; \
}
int main(){
int out;
int total = 5;
sum(5, out);
printf("out= %i original total=%i\n", out, total);
}
AM_CFLAGS=`pkg-config --cflags glib-2.0` -O3 -Wall
lib_LTLIBRARIES=libdict.la
libdict_la_SOURCES=dict.c keyval.c
include_HEADERS=keyval.h dict.h
bin_PROGRAMS=dict_use
dict_use_SOURCES=dict_use.c
dict_use_LDADD=libdict.la
TESTS=$(check_PROGRAMS)
check_PROGRAMS=dict_test
dict_test_LDADD=libdict.la
/* See compilation notes in dict_use.c*/
#include <stdio.h>
#include <stdlib.h>
#include "dict.h"
void *dictionary_not_found;
dictionary *dictionary_new (void){
static int dnf;
if (!dictionary_not_found) dictionary_not_found = &dnf;
dictionary *out= malloc(sizeof(dictionary));
*out= (dictionary){ };
return out;
}
static void dictionary_add_keyval(dictionary *in, keyval *kv){
in->length++;
in->pairs = realloc(in->pairs, sizeof(keyval*)*in->length);
in->pairs[in->length-1] = kv;
}
void dictionary_add(dictionary *in, char *key, void *value){
if (!key){fprintf(stderr, "NULL is not a valid key.\n"); abort();}
dictionary_add_keyval(in, keyval_new(key, value));
}
void *dictionary_find(dictionary const *in, char const *key){
for (int i=0; i< in->length; i++)
if (keyval_matches(in->pairs[i], key))
return in->pairs[i]->value;
return dictionary_not_found;
}
dictionary *dictionary_copy(dictionary *in){
dictionary *out = dictionary_new();
for (int i=0; i< in->length; i++)
dictionary_add_keyval(out, keyval_copy(in->pairs[i]));
return out;
}
void dictionary_free(dictionary *in){
for (int i=0; i< in->length; i++)
keyval_free(in->pairs[i]);
free(in);
}
/* See compilation notes in dict_use.c*/
#include "keyval.h"
extern void *dictionary_not_found;
typedef struct dictionary{
keyval **pairs;
int length;
} dictionary;
dictionary *dictionary_new (void);
dictionary *dictionary_copy(dictionary *in);
void dictionary_free(dictionary *in);
void dictionary_add(dictionary *in, char *key, void *value);
void *dictionary_find(dictionary const *in, char const *key);
/* Suggested makefile:
----------
#Or, use the script in dict_use.c to use as an Autotools build check.
CFLAGS=-g -Wall -O3 `pkg-config --cflags glib-2.0`
LDADD=`pkg-config --libs glib-2.0`
dict_test: dict.o keyval.o
----------
*/
#include <glib.h>
#include "dict.h"
typedef struct {
dictionary *dd;
} dfixture;
void dict_setup(dfixture *df, gconstpointer test_data){
df->dd = dictionary_new();
dictionary_add(df->dd, "key1", "val1");
dictionary_add(df->dd, "key2", NULL);
}
void dict_teardown(dfixture *df, gconstpointer test_data){
dictionary_free(df->dd);
}
void check_keys(dictionary const *d){
char *got_it = dictionary_find(d, "xx");
g_assert(got_it == dictionary_not_found);
got_it = dictionary_find(d, "key1");
g_assert_cmpstr(got_it, ==, "val1");
got_it = dictionary_find(d, "key2");
g_assert_cmpstr(got_it, ==, NULL);
}
void test_new(dfixture *df, gconstpointer ignored){
check_keys(df->dd);
}
void test_copy(dfixture *df, gconstpointer ignored){
dictionary *cp = dictionary_copy(df->dd);
check_keys(cp);
dictionary_free(cp);
}
void test_failure(){
if (g_test_trap_fork(0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)){
dictionary *dd = dictionary_new();
dictionary_add(dd, NULL, "blank");
}
g_test_trap_assert_failed();
g_test_trap_assert_stderr("NULL is not a valid key.\n");
}
int main(int argc, char **argv){
g_test_init(&argc, &argv, NULL);
g_test_add ("/set1/new test", dfixture, NULL,
dict_setup, test_new, dict_teardown);
g_test_add ("/set1/copy test", dfixture, NULL,
dict_setup, test_copy, dict_teardown);
g_test_add_func ("/set2/fail test", test_failure);
return g_test_run();
}
/* Compile with:
mkdir -p hash
cp dict_use.c dict.h dict.c keyval.c keyval.h dict_test.c hash
cp dict.automake hash/Makefile.am
cd hash
touch NEWS README AUTHORS ChangeLog #still cheating
autoscan
sed -e 's/FULL-PACKAGE-NAME/hashdict/' \
-e 's/VERSION/1/' \
-e 's|BUG-REPORT-ADDRESS|/dev/null|' \
-e '12i\
AM_INIT_AUTOMAKE' \
-e '13i\
LT_INIT' \
-e '14i\
AC_CHECK_LIB([glib-2.0],[g_free])' \
-e 's|PROG_CC|PROG_CC_C99|' \
< configure.scan > configure.ac
autoreconf -i > /dev/null
./configure
make distcheck
make
*/
#include <stdio.h>
#include "dict.h"
int main(){
int zero = 0;
float one = 1.0;
char two[] = "two";
dictionary *d = dictionary_new();
dictionary_add(d, "an int", &zero);
dictionary_add(d, "a float", &one);
dictionary_add(d, "a string", &two);
printf("The integer I recorded was: %i\n", *(int*)dictionary_find(d, "an int"));
printf("The string was: %s\n", (char*)dictionary_find(d, "a string"));
dictionary_free(d);
}
/* Compile with:
LDLIBS="-lm -ldl -lreadline" CFLAGS="-g -Wall -std=gnu11 -O3" make dynamic
*/
#define _GNU_SOURCE //cause stdio.h to include asprintf
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
void get_a_function(){
FILE *f = fopen("fn.c", "w");
fprintf(f, "#include <math.h>\n"
"double fn(double in){\n");
char *a_line = NULL;
char *header = ">>double fn(double in){\n>> ";
do {
free(a_line);
a_line = readline(header);
fprintf(f, "%s\n", a_line);
header = ">> ";
} while (strcmp(a_line, "}"));
fclose(f);
}
void compile_and_run(){
char *run_me;
asprintf(&run_me, "c99 -fPIC -shared fn.c -o fn.so");
if (system(run_me)!=0){
printf("Compilation error.");
return;
}
void *handle = dlopen("fn.so", RTLD_LAZY);
if (!handle) printf("Failed to load fn.so: %s\n", dlerror());
typedef double (*fn_type)(double);
fn_type f = dlsym(handle, "fn");
printf("f(1) = %g\n", f(1));
printf("f(2) = %g\n", f(2));
printf("f(10) = %g\n", f(10));
}
int main(){
printf("I am about to run a function. But first, you have to write it for me.\n"
"Enter the function body. Conclude with a '}' alone on a line.\n\n");
get_a_function();
compile_and_run();
}
/* Compile with:
make erf LDLIBS="-lm" CFLAGS="-g -Wall -std=gnu11 -O3"
*/
#include <math.h> //erf, sqrt
#include <stdio.h> //printf
int main(){
printf("The integral of a Normal(0, 1) distribution "
"between -1.96 and 1.96 is: %g\n", erf(1.96*sqrt(1/2.)));
}
/* Compile with:
make errortuple CFLAGS="-g -Wall -std=gnu11 -O3"
*/
#include <stdio.h>
#include <math.h> //NaN, pow
#define make_err_s(intype, shortname) \
typedef struct { \
intype value; \
char const *error; \
} shortname##_err_s;
make_err_s(double, double)
make_err_s(int, int)
make_err_s(char *, string)
double_err_s free_fall_energy(double time, double mass){
double_err_s out = {}; //initialize to all zeros.
out.error = time < 0 ? "negative time"
: mass < 0 ? "negative mass"
: isnan(time) ? "NaN time"
: isnan(mass) ? "NaN mass"
: NULL;
if (out.error) return out;
double velocity = 9.8*time;
out.value = mass*pow(velocity,2)/2.;
return out;
}
#define Check_err(checkme, return_val) \
if (checkme.error) {fprintf(stderr, "error: %s\n", checkme.error); return return_val;}
int main(){
double notime=0, fraction=0;
double_err_s energy = free_fall_energy(1, 1);
Check_err(energy, 1);
printf("Energy after one second: %g Joules\n", energy.value);
energy = free_fall_energy(2, 1);
Check_err(energy, 1);
printf("Energy after two seconds: %g Joules\n", energy.value);
energy = free_fall_energy(notime/fraction, 1);
Check_err(energy, 1);
printf("Energy after 0/0 seconds: %g Joules\n", energy.value);
}
/* Compile with:
make fibo CFLAGS="-g -Wall -std=gnu11 -O3"
*/
#include <stdio.h>
long long int fibonacci(){
static long long int first = 0;
static long long int second = 1;
long long int out = first+second;
first=second;
second=out;
return out;
}
int main(){
for (int i=0; i< 50; i++)
printf("%lli\n", fibonacci());
}
if [ ! -e moby ] ; then
curl -A "Mozilla/4.0" http://www.gutenberg.org/cache/epub/2701/pg2701.txt \
| sed -e '1,/START OF THIS PROJECT GUTENBERG/d' \
| sed -e '/End of Project Gutenberg/,$d' \
> moby
fi
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make floatfail
*/
#include <stdio.h>
int main(){
printf("%f\n", (float)333334126.98);
printf("%f\n", (float)333334125.31);
}
/* See compilation notes in cetology.c*/
#include "fstr.h"
#include "string_utilities.h"
fstr_s *fstr_new(char const *filename){
fstr_s *out = malloc(sizeof(fstr_s));
*out = (fstr_s){.start=0, .refs=malloc(sizeof(int))};
out->data = string_from_file(filename);
out->end = out->data ? strlen(out->data): 0;
*out->refs = 1;
return out;
}
fstr_s *fstr_copy(fstr_s const *in, size_t start, size_t len){
fstr_s *out = malloc(sizeof(fstr_s));
*out=*in;
out->start += start;
if (in->end > out->start + len)
out->end = out->start + len;
(*out->refs)++;
return out;
}
void fstr_free(fstr_s *in){
(*in->refs)--;
if (!*in->refs) {
free(in->data);
free(in->refs);
}
free(in);
}
fstr_list fstr_split (fstr_s const *in, gchar const *start_pattern){
if (!in->data) return (fstr_list){ };
fstr_s **out=malloc(sizeof(fstr_s*));
int outlen = 1;
out[0] = fstr_copy(in, 0, in->end);
GRegex *start_regex = g_regex_new (start_pattern, 0, 0, NULL);
gint mstart=0, mend=0;
fstr_s *remaining = fstr_copy(in, 0, in->end);
do {
GMatchInfo *start_info;
g_regex_match(start_regex, &remaining->data[remaining->start],
0, &start_info);
g_match_info_fetch_pos(start_info, 0, &mstart, &mend);
g_match_info_free(start_info);
if (mend > 0 && mend < remaining->end - remaining->start){
out = realloc(out, ++outlen * sizeof(fstr_s*));
out[outlen-1] = fstr_copy(remaining, mend, remaining->end-mend);
out[outlen-2]->end = remaining->start + mstart;
remaining->start += mend;
} else break;
} while (1);
fstr_free(remaining);
g_regex_unref(start_regex);
return (fstr_list){.strings=out, .count=outlen};
}
void fstr_list_free(fstr_list in){
for (int i=0; i< in.count; i++){
fstr_free(in.strings[i]);
}
free(in.strings);
}
void fstr_show(fstr_s const *fstr){
printf("%.*s", (int)fstr->end-fstr->start, &fstr->data[fstr->start]);
}
/* See compilation notes in cetology.c*/
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
typedef struct {
char *data;
size_t start, end;
int* refs;
} fstr_s;
fstr_s *fstr_new(char const *filename);
fstr_s *fstr_copy(fstr_s const *in, size_t start, size_t len);
void fstr_show(fstr_s const *fstr);
void fstr_free(fstr_s *in);
typedef struct {
fstr_s **strings;
int count;
} fstr_list;
fstr_list fstr_split (fstr_s const *in, gchar const *start_pattern);
void fstr_list_free(fstr_list in);
cat > makefile << '------'
P=dict_test
objects = keyval.o dict.o
CFLAGS = `pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -fprofile-arcs -ftest-coverage
LDLIBS = `pkg-config --libs glib-2.0`
CC=gcc
$(P):$(objects)
------
make
./dict_test
for i in *gcda; do gcov $i; done;
grep -C3 '#####' *.c.gcov
define phead
set $ptr = $arg1
plistdata $arg0
end
document phead
Print the first element of a list. E.g., given the declaration
Glist *datalist;
g_list_add(datalist, "Hello");
view the list with something like
gdb> phead char datalist
gdb> pnext char
gdb> pnext char
This macro defines $ptr as the current pointed-to list struct,
and $pdata as the data in that list element.
end
define pnext
set $ptr = $ptr->next
plistdata $arg0
end
document pnext
You need to call phead first; that will set $ptr.
This macro will step forward in the list, then show the value at
that next element. Give the type of the list data as the only argument.
This macro defines $ptr as the current pointed-to list struct, and
$pdata as the data in that list element.
end
define plistdata
if $ptr
set $pdata = $ptr->data
else
set $pdata= 0
end<?dbfo-need height="1in"
?>
if $pdata
p ($arg0*)$pdata
else
p "NULL"
end
end
document plistdata
This is intended to be used by phead and pnext, q.v. It sets $pdata and prints its value.
end
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make getenv
#Sample usage
reps=10 msg="Ha" ./getenv
msg="Ha" ./getenv
reps=20 msg=" " ./getenv
*/
#include <stdlib.h> //getenv, atoi
#include <stdio.h> //printf
int main(){
char *repstext = getenv("reps");
int reps = repstext ? atoi(repstext) : 10;
char *msg = getenv("msg");
if (!msg) msg = "Hello.";
for (int i=0; i< reps; i++)
printf("%s\n", msg);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make getstrings
*/
#define _GNU_SOURCE //cause stdio.h to include asprintf
#include <stdio.h>
#include <stdlib.h> //free
void get_strings(char const *in){
char *cmd;
asprintf(&cmd, "strings %s", in);
if (system(cmd)) fprintf(stderr, "something went wrong running %s.\n", cmd);
free(cmd);
}
int main(int argc, char **argv){
get_strings(argv[0]);
}
/* Compile with:
export CFLAGS="`pkg-config --cflags glib-2.0` -g -Wall -std=gnu11 -O3"
export LDLIBS="`pkg-config --libs glib-2.0`"
make glist
*/
#include <stdio.h>
#include <glib.h>
GList *list;
int main(){
list = g_list_append(list, "a");
list = g_list_append(list, "b");
list = g_list_append(list, "c");
for ( ; list!= NULL; list=list->next)
printf("%s\n", (char*)list->data);
}
@
/* Suggested makefile:
----------
#GNU make knows how to run ctangle groupabm.w to generate groupabm.c.
#If you have TeX installed, also try "make groupabm.tex; pdftex groupabm.tex" .
P = groupabm
objects = groups.o
CFLAGS=`pkg-config --cflags glib-2.0 apophenia` -std=gnu11 -g -Wall -O3
LDLIBS=`pkg-config --libs glib-2.0 apophenia`
$(P): $(objects)
----------
*/
@* Initializations.
@ This is the part of the agent-based model with the handlers for the
|people| structures and the procedure itself.
At this point all interface with the groups happens via the
new/join/exit/print functions from |groups.cweb.c|. Thus, there is zero
memory management code in this file--the reference counting guarantees us
that when the last member exits a group, the group will be freed.
@c
#include "groups.h"
int pop=2000,
periods=200,
dimension=2;
@ In |main|, we'll initialize a few constants that we can't have as static
variables because they require math.
@<set up more constants@>=
double new_group_odds = 1./pop,
mass_benefit = .7/pop;
gsl_rng *r = apop_rng_alloc(1234);
@ The people in this simulation are pretty boring: they do not die, and do
not move. So the struct that represents them is simple, with just |position|
and a pointer to the group of which the agent is currently a member.
@c
typedef struct {
gsl_vector *position;
group_s *group;
} person_s;
@ The setup routine is also boring, and consists of allocating a uniform
random vector in two dimensions.
@c
person_s person_setup(gsl_rng *r){
gsl_vector *posn = gsl_vector_alloc(dimension);
for (int i=0; i< dimension; i++)
gsl_vector_set(posn, i, 2*gsl_rng_uniform(r)-1);
return (person_s){.position=posn};
}
@* Group membersip.
@ At the outset of this function, the person leaves its group.
Then, the decision is only whether to form a new group or join an existing one.
@c
void check_membership(person_s *p, gsl_rng *r,
double mass_benefit, double new_group_odds){
group_exit(p->group, p->position);
p->group = (gsl_rng_uniform(r) < new_group_odds)
? @<form a new group@>
: @<join the closest group@>;
}
@
@<form a new group@>=
group_new(p->position)
@
@<join the closest group@>=
group_join(group_closest(p->position, mass_benefit), p->position)
@* Simulation startup.
@ The initialization of the population. Using CWEB's macros, it is at this point
self-documenting.
@c
void init(person_s *people, int pop, gsl_rng *r){
@<position everybody@>
@<start with ten groups@>
@<everybody joins a group@>
}
@
@<position everybody@>=
for (int i=0; i< pop; i++)
people[i] = person_setup(r);
@ The first ten people in our list form new groups, but because everybody's
position is random, this is assigning the ten groups at random.
@<start with ten groups@>=
for (int i=0; i< 10; i++)
people[i].group = group_new(people[i].position);
@
@<everybody joins a group@>=
for (int i=10; i< pop; i++)
people[i].group = group_join(people[i%10].group, people[i].position);
@* Plotting.
@ This is the header for Gnuplot. I arrived at it by manually playing
around with Gnuplot, then writing down my final picks for settings here.
@<print the Gnuplot header@>=
printf("unset key;set xrange [-1:1]\nset yrange [-1:1]\n");
@ Gnuplot animation simply consists of sending a sequence of plot statements.
@<plot one animation frame@>=
print_groups();
@* |main|.
@ The |main| routine consists of a few setup steps, and a simple loop:
calculate a new state, then plot it.
@c
int main(){
@<set up more constants@>
person_s people[pop];
init(people, pop, r);
@<print the Gnuplot header@>
for (int t=0; t< periods; t++){
for (int i=0; i< pop; i++)
check_membership(&people[i], r, mass_benefit, new_group_odds);
@<plot one animation frame@>
}
}
/* See compilation notes in groupabm.w*/
#include <apop.h>
#include <glib.h>
typedef struct {
gsl_vector *position;
int id, size;
} group_s;
group_s* group_new(gsl_vector *position);
group_s* group_join(group_s *joinme, gsl_vector *position);
void group_exit(group_s *leaveme, gsl_vector *position);
group_s* group_closest(gsl_vector *position, double mb);
void print_groups();
@
/* See compilation notes in groupabm.w*/
@ Here in the introductory material, we include the header and specify
the global list of groups that the program makes use of. We'll need
new/copy/free functions for each group.
@c
#include "groups.h"
GList *group_list;
@<new group@>
@<copy group@>
@<free group@>
@ The new group method is boilerplate: we |malloc| some space,
fill the struct using designated initializers, and append the newly-formed
group to the list.
@<new group@>=
group_s *group_new(gsl_vector *position){
static int id=0;
group_s *out = malloc(sizeof(group_s));
*out = (group_s) {.position=apop_vector_copy(position), .id=id++, .size=1};
group_list = g_list_append(group_list, out);
return out;
}
@ When an agent joins a group, the group is `copied' to the agent, but
there isn't any memory being copied: the group is simply modified to
accommodate the new person. We have to increment the reference count, which
is easy enough, and then modify the mean position. If the mean position
without the $n$th person is $P_{n-1}$, and the $n$th person is at position
$p$, then the new mean position with the person, $P_n$ is the weighted sum.
$$P_n = \left( (n-1)P_{n-1}/n \right) + p/n.$$
We calculate that for each dimension.
@<copy group@>=
group_s *group_join(group_s *joinme, gsl_vector *position){
int n = ++joinme->size; //increment the reference count
for (int i=0; i< joinme->position->size; i++){
joinme->position->data[i] *= (n-1.)/n;
joinme->position->data[i] += position->data[i]/n;
}
return joinme;
}
@ The `free` function really only frees the group when the reference count
is zero. When it isn't, then we need to run the data-augmenting formula
for the mean in reverse to remove a person.
@<free group@>=
void group_exit(group_s *leaveme, gsl_vector *position){
int n = leaveme->size--; //lower the reference count
for (int i=0; i< leaveme->position->size; i++){
leaveme->position->data[i] -= position->data[i]/n;
leaveme->position->data[i] *= n/(n-1.);
}
if (leaveme->size == 0){ //garbage collect?
gsl_vector_free(leaveme->position);
group_list= g_list_remove(group_list, leaveme);
free(leaveme);
}
}
@ I played around a lot with different rules for how exactly people
evaluate the distance to the groups. In the end, I wound up using the $L_3$
norm. The standard distance is the $L_2$ norm, aka Euclidian distance,
meaning that the distance between $(x_1, y_1)$ and $(x_2, y_2)$ is
$\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}$. This is $L_3$,
$\sqrt[3]{(x_1-x_2)^3+(y_1-y_2)^3}$.
This and the call to |apop_copy| above are the only calls to the Apophenia
library; you could write around them if you don't have that library on hand.
@<distance@>=
apop_vector_distance(g->position, position, .metric='L', .norm=3)
@ By `closest', I mean the group that provides the greatest benefit,
by having the smallest distance minus weighted size. Given the utility
function represented by the |dist| line, this is just a simple |for|
loop to find the smallest distance.
@c
group_s *group_closest(gsl_vector *position, double mass_benefit){
group_s *fave=NULL;
double smallest_dist=GSL_POSINF;
for (GList *gl=group_list; gl!= NULL; gl = gl->next){
group_s *g = gl->data;
double dist= @<distance@> - mass_benefit*g->size;
if(dist < smallest_dist){
smallest_dist = dist;
fave = g;
}
}
return fave;
}
@ Gnuplot is automation-friendly. Here we get an animated simulation with
four lines of plotting code. The header |plot '-'| tells the system to plot
the data to follow, then we print the $(X, Y)$ positions, one to a line. The
final |e| indicates the end of the data set. The main program will set some
initial Gnuplot settings.
@c
void print_groups(){
printf("plot '-' with points pointtype 6\n");
for (GList *gl=group_list; gl!= NULL; gl = gl->next)
apop_vector_print(((group_s*)gl->data)->position);
printf("e\n");
}
/* Compile with:
export LDLIBS="`pkg-config --libs apophenia`"
export CFLAGS="`pkg-config --cflags apophenia` -g -Wall -O3"
export CC=c99
make gsl_distance
*/
#include <apop.h>
double one_dist(gsl_vector *v1, void *v2){
return apop_vector_distance(v1, v2);
}
long double distance(apop_data *data, apop_model *model){
gsl_vector *target = model->parameters->vector;
return -apop_map_sum(data, .fn_vp=one_dist, .param=target, .part='r');
}
apop_model *min_distance= &(apop_model){
.name="Minimum distance to a set of input points.", .p=distance, .vsize=-1};
int main(){
apop_data *locations = apop_data_falloc((5, 2),
1.1, 2.2,
4.8, 7.4,
2.9, 8.6,
-1.3, 3.7,
2.9, 1.1);
Apop_model_add_group(min_distance, apop_mle, .method= APOP_SIMPLEX_NM,
.tolerance=1e-5);
Apop_model_add_group(min_distance, apop_parts_wanted);
apop_model *est=apop_estimate(locations, min_distance);
apop_model_show(est);
}
/* Compile with:
export LDLIBS="`pkg-config --libs gsl`"
export CFLAGS="`pkg-config --cflags gsl` -g -Wall -std=gnu11 -O3"
make gsl_erf
*/
#include <gsl/gsl_cdf.h>
#include <stdio.h>
int main(){
double bottom_tail = gsl_cdf_gaussian_P(-1.96, 1);
printf("Area between [-1.96, 1.96]: %g\n", 1-2*bottom_tail);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make ideal
*/
#include <stdio.h>
typedef struct {
double pressure, moles, temp;
} ideal_struct;
/** Find the volume (in cubic meters) via the ideal gas law: V =nRT/P
Inputs:
pressure in atmospheres (default 1)
moles of material (default 1)
temperature in Kelvins (default freezing = 273.15)
*/
#define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1, \
.moles=1, .temp=273.15, __VA_ARGS__})
double ideal_pressure_base(ideal_struct in){
return 8.314 * in.moles*in.temp/in.pressure;
}
int main(){
printf("volume given defaults: %g\n", ideal_pressure() );
printf("volume given boiling temp: %g\n", ideal_pressure(.temp=373.15) );
printf("volume given two moles: %g\n", ideal_pressure(.moles=2) );
printf("volume given two boiling moles: %g\n",
ideal_pressure(.moles=2, .temp=373.15) );
}
/* This is cut down from ideal.c, providing only that which is needed for
a header. The Python package will use this. */
typedef struct {
double pressure, moles, temp;
} ideal_struct;
/** Find the volume (in cubic meters) via the ideal gas law: V =nRT/P
Inputs:
pressure in atmospheres (default 1)
moles of material (default 1)
temperature in Kelvins (default freezing = 273.15)
*/
#define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1, \
.moles=1, .temp=273.15, __VA_ARGS__})
double ideal_pressure_base(ideal_struct in);
if test ! -e a_test_file; then
echo test file had not existed
touch a_test_file
else
echo test file existed
rm a_test_file
fi
/* Compile with:
export CFLAGS="-g -std=gnu11 -O3" #The usual, but without -Wall
make iggy_pop_detector #Still, this will throw a warning
*/
#include <stdbool.h>
#include <strings.h> //strcasecmp (from POSIX)
bool check_name(char const **in){
return (!strcasecmp(in[0], "Iggy") && !strcasecmp(in[1], "Pop"))
||(!strcasecmp(in[0], "James") && !strcasecmp(in[1], "Osterberg"));
}
int main(int argc, char **argv){
if (argc < 2) return 0;
return check_name(&argv[1]);
}
/* Compile with:
make intptr CFLAGS="-g -Wall -std=gnu11"
*/
#include <stdio.h>
#include <stdint.h> //intptr_t
int main(){
char *astring = "I am somwhere in memory.";
intptr_t location = (intptr_t)astring;
printf("%s\n", (char*)location);
}
/* See compilation notes in dict_use.c*/
#include <stdlib.h> //malloc
#include <strings.h> //strcasecmp (from POSIX)
#include "keyval.h"
keyval *keyval_new(char *key, void *value){
keyval *out = malloc(sizeof(keyval));
*out = (keyval){.key = key, .value=value};
return out;
}
/** Copy a key/value pair. The new pair has pointers to
the values in the old pair, not copies of their data. */
keyval *keyval_copy(keyval const *in){
keyval *out = malloc(sizeof(keyval));
*out = *in;
return out;
}
void keyval_free(keyval *in){ free(in); }
int keyval_matches(keyval const *in, char const *key){
return !strcasecmp(in->key, key);
}
/* See compilation notes in dict_use.c*/
typedef struct keyval{
char *key;
void *value;
} keyval;
keyval *keyval_new(char *key, void *value);
keyval *keyval_copy(keyval const *in);
void keyval_free(keyval *in);
int keyval_matches(keyval const *in, char const *key);
# Count lines with a ;, ), or }, and let that count be named Lines.
Lines=`grep '[;)}]' *.c | wc -l`
# Now count how many lines there are in a directory listing;
# name it Files.
Files=`ls *.c |wc -l`
echo files=$Files and lines=$Lines
# Arithmetic expansion is a double-paren.
# In bash, the remainder is truncated; more on this later.
echo lines/file = $(($Lines/$Files))
# Or, use those variables in a here script.
# By setting scale=3, answers are printed to 3 decimal places.
bc << ---
scale=3
$Lines/$Files
---
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make macro_varargs
*/
#define _GNU_SOURCE //cause stdio.h to include vasprintf
#include <stdio.h> //printf, vasprintf
#include <stdlib.h> //system
#include <assert.h>
#define System_w_printf(outval, ...) { \
char *string_for_systemf; \
asprintf(&string_for_systemf, __VA_ARGS__); \
outval = system(string_for_systemf); \
free(string_for_systemf); \
}
int main(int argc, char **argv){
assert(argc == 2);
int out;
System_w_printf(out, "ls %s", argv[1]);
return out;
}
push:
@if [ "x$(MSG)" = 'x' ] ; then \
echo "Usage: MSG='whatever.' make push"; fi
@test "x$(MSG)" != 'x'
git commit -a -m "$(MSG)"
git svn fetch
git svn rebase
git svn dcommit
pull:
git svn fetch
git svn rebase
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make memmove
*/
#include <assert.h>
#include <string.h> //memmove
int main(){
int abc[] = {0, 1, 2};
int *copy1, copy2[3];
copy1 = abc;
memmove(copy2, abc, sizeof(int)*3);
abc[0] = 3;
assert(copy1[0]==3);
assert(copy2[0]==0);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make mmap
*/
#include <stdio.h>
#include <unistd.h> //lseek, write, close
#include <stdlib.h> //exit
#include <fcntl.h> //open
#include <sys/mman.h>
#include "stopif.h"
#define Mapmalloc(number, type, filename, fd) \
load_mmap((filename), &(fd), (number)*sizeof(type), 'y')
#define Mapload(number, type, filename, fd) \
load_mmap((filename), &(fd), (number)*sizeof(type), 'n')
#define Mapfree(number, type, fd, pointer) \
releasemmap((pointer), (number)*sizeof(type), (fd))
void *load_mmap(char const *filename, int *fd, size_t size, char make_room){
*fd = open(filename,
make_room=='y' ? O_RDWR | O_CREAT | O_TRUNC : O_RDWR,
(mode_t)0600);
Stopif(*fd == -1, return NULL, "Error opening file");
if (make_room=='y'){ // Stretch the file size to the size of the (mmapped) array
int result = lseek(*fd, size-1, SEEK_SET);
Stopif(result == -1, close(*fd); return NULL, "Error calling lseek() to stretch the file");
result = write(*fd, "", 1);
Stopif(result != 1, close(*fd); return NULL, "Error writing last byte of the file");
}
void *map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
Stopif(map == MAP_FAILED, return NULL, "Error mmapping the file");
return map;
}
int releasemmap(void *map, size_t size, int fd){
Stopif(munmap(map, size) == -1, return -1, "Error un-mmapping the file");
close(fd);
return 0;
}
int main(int argc, char *argv[]) {
int fd;
long int N=1e5+6;
int *map = Mapmalloc(N, int, "mmapped.bin", fd);
for (long int i = 0; i <N; ++i) map[i] = i;
Mapfree(N, int, fd, map);
//Now reopen and do some counting.
int *readme = Mapload(N, int, "mmapped.bin", fd);
long long int oddsum=0;
for (long int i = 0; i <N; ++i) if (readme[i]%2) oddsum += i;
printf("The sum of odd numbers up to %li: %lli\n", N, oddsum);
Mapfree(N, int, fd, readme);
}
/* Suggested makefile:
----------
P=mutex_wc
objects=string_utilities.o
# To use Glib mutexes, some systems will require both glib-2.0 and gthread-2.0.
CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3 -pthread
LDLIBS=`pkg-config --libs glib-2.0` -lpthread
$(P): $(objects)
----------
*/
#include "string_utilities.h"
#include <pthread.h>
#include <glib.h> //mutexes
long int global_wc;
typedef struct{
int wc;
char *docname;
} wc_struct;
void *wc(void *voidin){
wc_struct *in = voidin;
char *doc = string_from_file(in->docname);
if (!doc) return NULL;
static GMutex count_lock;
char *delimiters = " `~!@#$%^&*()_-+={[]}|\\;:\",<>./?\n\t";
ok_array *words = ok_array_new(doc, delimiters);
if (!words) return NULL;
in->wc = words->length;
ok_array_free(words);
g_mutex_lock(&count_lock);
for (int i=0; i< in->wc; i++)
global_wc++; //a slow global_wc += in->wc;
g_mutex_unlock(&count_lock);
return NULL;
}
int main(int argc, char **argv){
argc--;
argv++; //step past the name of the program.
pthread_t threads[argc];
wc_struct s[argc];
for (int i=0; i< argc; i++){
s[i] = (wc_struct){.docname=argv[i]};
pthread_create(&threads[i], NULL, wc, &s[i]);
}
int values[argc];
for (int i=0; i< argc; i++){
pthread_join(threads[i], NULL);
values[i] = s[i].wc;
}
for (int i=0; i< argc; i++) printf("%s:\t%i\n",argv[i], values[i]);
printf("The total: %li\n", global_wc);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make na
*/
#include <stdio.h>
#include <math.h> //isnan
double ref;
double set_na(){
if (!ref) {
ref=0/0.;
char *cr = (char *)(&ref);
cr[2]='a';
}
return ref;
}
int is_na(double in){
if (!ref) return 0; //set_na was never called==>no NAs yet.
char *cc = (char *)(&in);
char *cr = (char *)(&ref);
for (int i=0; i< sizeof(double); i++)
if (cc[i] != cr[i]) return 0;
return 1;
}
int main(){
double x = set_na();
double y = x;
printf("Is x=set_na() NA? %i\n", is_na(x));
printf("Is x=set_na() NAN? %i\n", isnan(x));
printf("Is y=x NA? %i\n", is_na(y));
printf("Is 0/0 NA? %i\n", is_na(0/0.));
printf("Is 8 NA? %i\n", is_na(8));
}
/** \file
A program to read in the NYT's headline feed and produce a simple
HTML page from the headlines. */
#include <stdio.h>
#include <curl/curl.h>
#include <libxml2/libxml/xpath.h>
#include "stopif.h"
/** \mainpage
The front page of the Grey Lady's web site is as gaudy as can be, including
several headlines and sections trying to get your attention, various formatting
schemes, and even photographs--in <em>color</em>.
This program reads in the NYT Headlines RSS feed, and writes a simple list in
plain HTML. You can then click through to the headline that modestly piques
your attention.
For notes on compilation, see the \ref compilation page.
*/
/** \page compilation Compiling the program
Save the following code to \c makefile.
Notice that cURL has a program, \c curl-config, that behaves like \c pkg-config,
but is cURL-specific.
\code
CFLAGS =-g -Wall -O3 `curl-config --cflags` -I/usr/include/libxml2
LDLIBS=`curl-config --libs ` -lxml2
CC=c99
nyt_feed:
\endcode
Having saved your makefile, use <tt>make nyt_feed</tt> to compile.
Of course, you have to have the development packages for libcurl and libxml2
installed for this to work.
*/
//These have in-line Doxygen documentation. The < points to the prior text
//being documented.
char *rss_url = "http://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml";
/**< The URL for an NYT RSS. */
char *rssfile = "nytimes_feeds.rss"; /**< A local file to write the RSS to.*/
char *outfile = "now.html"; /**< The output file to open in your browser.*/
/** Print a list of headlines in HTML format to the outfile, which is overwritten.
\param urls The list of urls. This should have been tested for non-NULLness
\param titles The list of titles, also pre-tested to be non-NULL. If the length
of the \c urls list or the \c titles list is \c NULL, this will crash.
*/
void print_to_html(xmlXPathObjectPtr urls, xmlXPathObjectPtr titles){
FILE *f = fopen(outfile, "w");
for (int i=0; i< titles->nodesetval->nodeNr; i++)
fprintf(f, "<a href=\"%s\">%s</a><br>\n"
, xmlNodeGetContent(urls->nodesetval->nodeTab[i])
, xmlNodeGetContent(titles->nodesetval->nodeTab[i]));
fclose(f);
}
/** Parse an RSS feed on the hard drive. This will parse the XML, then find
all nodes matching the XPath for the title elements and all nodes matching
the XPath for the links. Then, it will write those to the outfile.
\param infile The RSS file in.
*/
int parse(char const *infile){
const xmlChar *titlepath= (xmlChar*)"//item/title";
const xmlChar *linkpath= (xmlChar*)"//item/link";
xmlDocPtr doc = xmlParseFile(infile);
Stopif(!doc, return -1, "Error: unable to parse file \"%s\"\n", infile);
xmlXPathContextPtr context = xmlXPathNewContext(doc);
Stopif(!context, return -2, "Error: unable to create new XPath context\n");
xmlXPathObjectPtr titles = xmlXPathEvalExpression(titlepath, context);
xmlXPathObjectPtr urls = xmlXPathEvalExpression(linkpath, context);
Stopif(!titles || !urls, return -3, "either the Xpath '//item/title' "
"or '//item/link' failed.");
print_to_html(urls, titles);
xmlXPathFreeObject(titles);
xmlXPathFreeObject(urls);
xmlXPathFreeContext(context);
xmlFreeDoc(doc);
return 0;
}
/** Use cURL's easy interface to download the current RSS feed.
\param url The URL of the NY Times RSS feed. Any of the ones listed at
\url http://www.nytimes.com/services/xml/rss/nyt/ should work.
\param outfile The headline file to write to your hard drive. First save
the RSS feed to this location, then overwrite it with the short list of links.
\return 1==OK, 0==failure.
*/
int get_rss(char const *url, char const *outfile){
FILE *feedfile = fopen(outfile, "w");
if (!feedfile) return -1;
CURL *curl = curl_easy_init();
if(!curl) return -1;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, feedfile);
CURLcode res = curl_easy_perform(curl);
if (res) return -1;
curl_easy_cleanup(curl);
fclose(feedfile);
return 0;
}
int main(void) {
Stopif(get_rss(rss_url, rssfile), return 1, "failed to download %s to %s.\n",
rss_url, rssfile);
parse(rssfile);
printf("Wrote headlines to %s. Have a look at it in your browser.\n", outfile);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make olden_varargs
*/
#define _GNU_SOURCE //cause stdio.h to include vasprintf
#include <stdio.h> //printf, vasprintf
#include <stdarg.h> //va_start, va_end
#include <stdlib.h> //system, free
#include <assert.h>
int system_w_printf(char const *fmt, ...) __attribute__ ((format (printf,1,2)));
int system_w_printf(char const *fmt, ...){
char *cmd;
va_list argp;
va_start(argp, fmt);
vasprintf(&cmd, fmt, argp);
va_end(argp);
int out= system(cmd);
free(cmd);
return out;
}
int main(int argc, char **argv){
assert(argc == 2);
return system_w_printf("ls %s", argv[1]);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make papersize
*/
#include <stdio.h>
#include <strings.h> //strcasecmp (from POSIX)
#include <math.h> //NaN
typedef struct {
double width, height;
} size_s;
size_s width_height(char *papertype){
return
!strcasecmp(papertype, "A4") ? (size_s) {.width=210, .height=297}
: !strcasecmp(papertype, "Letter") ? (size_s) {.width=216, .height=279}
: !strcasecmp(papertype, "Legal") ? (size_s) {.width=216, .height=356}
: (size_s) {.width=NAN, .height=NAN};
}
int main(){
size_s a4size = width_height("a4");
printf("width= %g, height=%g\n", a4size.width, a4size.height);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make pointer_arithmetic1
*/
#include <stdio.h>
int main(){
char *list[] = {"first", "second", "third", NULL};
for (char **p=list; *p != NULL; p++){
printf("%s\n", p[0]);
}
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make pointer_arithmetic2
*/
#include <stdio.h>
typedef char* string;
int main(){
string list[] = {"first", "second", "third", NULL};
for (string *p=list; *p != NULL; p++){
printf("%s\n", *p);
}
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make preprocess
*/
#include <stdio.h>
#include <math.h> //NAN
#define Setup_list(name, ...) \
double *name ## _list = (double []){__VA_ARGS__, NAN}; \
int name ## _len = 0; \
for (name ## _len =0; \
!isnan(name ## _list[name ## _len]); \
) name ## _len ++;
int main(){
Setup_list(items, 1, 2, 4, 8);
double sum=0;
for (double *ptr= items_list; !isnan(*ptr); ptr++)
sum += *ptr;
printf("total for items list: %g\n", sum);
#define Length(in) in ## _len
sum=0;
Setup_list(next_set, -1, 2.2, 4.8, 0.1);
for (int i=0; i < Length(next_set); i++)
sum += next_set_list[i];
printf("total for next set list: %g\n", sum);
}
/* See compilation notes in show_tree.c or charct.c*/
#include "process_dir.h"
#define _GNU_SOURCE //cause stdio.h to include asprintf
#include <stdio.h> //asprintf
#include <dirent.h> //struct dirent
#include <stdlib.h> //free
int process_dir_r(filestruct level){
if (!level.fullname){
if (level.name) level.fullname=level.name;
else level.fullname=".";
}
int errct=0;
DIR *current=opendir(level.fullname);
if (!current) return 1;
struct dirent *entry;
while((entry=readdir(current))) {
if (entry->d_name[0]=='.') continue;
filestruct next_level = level;
next_level.name = entry->d_name;
asprintf(&next_level.fullname, "%s/%s", level.fullname, entry->d_name);
if (entry->d_type==DT_DIR){
next_level.depth ++;
if (level.directory_action) level.directory_action(next_level);
errct+= process_dir_r(next_level);
}
else if (entry->d_type==DT_REG && level.file_action){
level.file_action(next_level);
errct+= next_level.error;
}
free(next_level.fullname);
}
closedir(current);
return errct;
}
/* See compilation notes in show_tree.c or charct.c*/
struct filestruct;
typedef void (*level_fn)(struct filestruct path);
typedef struct filestruct{
char *name, *fullname;
level_fn directory_action, file_action;
int depth, error;
void *data;
} filestruct;
/** I get the contents of the given directory, run \c file_action on each
file, and for each directory run \c dir_action and recurse into the directory.
Note that this makes the traversal `depth first'.
Your functions will take in a \c filestruct, qv. Note that there is an \c error
element, which you can set to one to indicate an error.
Inputs are designated initializers, and may include:
\li \c .name The current file or directory name
\li \c .fullname The path of the current file or directory
\li \c .directory_action A function that takes in a \c filestruct.
I will call it with an appropriately-set \c filestruct
for every directory (just before the files in the directory
are processed).
\li \c .file_action Like the \c directory_action, but the function
I will call for every non-directory file.
\li \c .data A void pointer to be passed in to your functions.
\return 0=OK, otherwise the count of directories that failed + errors thrown by your scripts.
Your functions may change the \c data element of the \c filestruct.
Sample usage:
\code
void dirp(filestruct in){ printf("Directory: <%s>\n", in.name); }
void filep(filestruct in){ printf("File: %s\n", in.name); }
//list files, but not directories, in current dir:
process_dir(.file_action=filep);
//show everything in my home directory:
process_dir(.name="/home/b", .file_action=filep, .directory_action=dirp);
\endcode
*/
#define process_dir(...) process_dir_r((filestruct){__VA_ARGS__})
int process_dir_r(filestruct level);
/* Suggested makefile:
----------
P=pthreads
objects=string_utilities.o
# To use Glib mutexes, some systems will require both glib-2.0 and gthread-2.0.
CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3 -pthread
LDLIBS=`pkg-config --libs glib-2.0` -pthread
$(P): $(objects)
----------
*/
#include "stopif.h"
#include "string_utilities.h"
#include <pthread.h>
typedef struct{
int wc;
char *docname;
} wc_struct;
void *wc(void *voidin){
wc_struct *in = voidin;
char *doc = string_from_file(in->docname);
if (!doc) return NULL; // in->wc remains zero.
char *delimiters = " `~!@#$%^&*()_-+={[]}|\\;:\",<>./?\n";
ok_array *words = ok_array_new(doc, delimiters);
if (!words) return NULL;
in->wc = words->length;
ok_array_free(words);
return NULL;
}
int main(int argc, char **argv){
argc--;
argv++;
Stopif(!argc, return 0, "Please give some file names on the command line.");
pthread_t threads[argc];
wc_struct s[argc];
for (int i=0; i< argc; i++){
s[i] = (wc_struct){.docname=argv[i]};
pthread_create(&threads[i], NULL, wc, &s[i]);
}
for (int i=0; i< argc; i++) pthread_join(threads[i], NULL);
for (int i=0; i< argc; i++) printf("%s:\t%i\n",argv[i], s[i].wc);
}
P=pthreads
objects=string_utilities.o
# To use Glib mutexes, some systems will require both glib-2.0 and gthread-2.0.
CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3 -pthread
LDLIBS=`pkg-config --libs glib-2.0` -pthread
$(P): $(objects)
pyexec_LTLIBRARIES=libpvnrt.la
libpvnrt_la_SOURCES=ideal.c
SUBDIRS=.
if HAVE_PYTHON
SUBDIRS += py
endif
all-local: pvnrt
pvnrt:
CFLAGS='@CFLAGS@' python setup.py build
install-exec-hook:
python setup.py install
# This is a script to set up the Python demo. As per the text, there is
# a main directory with the C code, and a subdirectory with the Python part.
# Once those components are set up, run autoreconf to generate the components,
# then the usual ./configure; make; sudo make install.
if [ -e autodemo ]; then sudo rm -r autodemo; fi
mkdir -p autodemo
cp ../ideal.h ../ideal.c Makefile.am configure.ac autodemo/
cd autodemo
touch NEWS README AUTHORS ChangeLog #still cheating.
mkdir py
cp ../setup.py ../ideal.py.c py/
cp ../Makefile.py.am py/Makefile.am
autoreconf -iv
echo ----------configure------------
./configure
echo ----------make------------
make
echo ----------install------------
sudo make install
AC_PREREQ([2.68])
AC_INIT([pvnrt], [1], [/dev/null])
AC_CONFIG_SRCDIR([ideal.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE
AC_PROG_CC_C99
LT_INIT
AM_PATH_PYTHON(,, [:])
AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :])
if test "$PYTHON" != : ; then
AC_CONFIG_SUBDIRS([py])
fi
AC_CONFIG_FILES([Makefile py/Makefile])
AC_OUTPUT
/* See compilation notes in build.python*/
#include <Python.h>
#include "../ideal.h"
static PyObject *ideal_py(PyObject *self, PyObject *args){
double intemp;
if (!PyArg_ParseTuple(args, "d", &intemp)) return NULL;
double out = ideal_pressure(.temp=intemp);
return Py_BuildValue("d", out);
}
static PyMethodDef method_list[] = {
{"pressure_from_temp", ideal_py, METH_VARARGS,
"Get the pressure from the temperature of one mole of gunk"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initpvnrt(void) {
Py_InitModule("pvnrt", method_list);
}
from distutils.core import setup, Extension
py_modules= ['pvnrt']
Emodule = Extension('pvnrt',
libraries=['pvnrt'],
library_dirs=['..'],
sources = ['ideal.py.c'])
setup (name = 'pvnrt',
#provides='pvnrt',
version = '1.0',
description = 'pressure * volume = n * R * Temperature',
ext_modules = [Emodule])
/* Compile with:
make sadstrings CFLAGS="-g -Wall -std=gnu11 -O3"
*/
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h> //malloc, free, system
void get_strings(char const *in){
char *cmd;
int len = strlen("strings ") + strlen(in) + 1;
cmd = malloc(len);
snprintf(cmd, len, "strings %s", in);
if (system(cmd)) printf("something went wrong running %s.\n", cmd);
free(cmd);
}
int main(int argc, char **argv){
get_strings(argv[0]);
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make safe_sum
*/
#include <math.h> //NAN
#include <stdio.h>
double sum_array(double in[]){
double out=0;
for (int i=0; !isnan(in[i]); i++) out += in[i];
return out;
}
#define sum(...) sum_array((double[]){__VA_ARGS__, NAN})
int main(){
double two_and_two = sum(2, 2);
printf("2+2 = %g\n", two_and_two);
printf("(2+2)*3 = %g\n", sum(two_and_two, two_and_two, two_and_two));
printf("sum(asst) = %g\n", sum(3.1415, two_and_two, 3, 8, 98.4));
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual
make sasprintf
*/
#define _GNU_SOURCE //asks stdio.h to include asprintf
#include <stdio.h> //printf
#include <stdlib.h> //free
//Safer asprintf macro
#define Sasprintf(write_to, ...) { \
char *tmp_string_for_extend = (write_to); \
asprintf(&(write_to), __VA_ARGS__); \
free(tmp_string_for_extend); \
}
//sample usage:
int main(){
int i=3;
char *q = NULL;
Sasprintf(q, "select * from tab");
Sasprintf(q, "%s where col%i is not null", q, i);
printf("%s\n", q);
}
/* Compile with:
make LDLIBS='-lm' CFLAGS="-g -Wall -std=gnu11 --ms-extensions" seamlessone
*/
#include <stdio.h>
#include <math.h>
typedef struct point {
double x, y;
} point;
typedef struct {
struct point;
double z;
} threepoint;
double threelength (threepoint p){
return sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
}
int main(){
threepoint p = {.x=3, .y=0, .z=4};
printf("p is %g units from the origin\n", threelength(p));
}
/* Compile with:
make LDLIBS='-lm' CFLAGS="-g -Wall -std=gnu11 --ms-extensions" seamlesstwo
*/
#include <stdio.h>
#include <math.h>
typedef struct point {
double x, y;
} point;
typedef struct {
union {
struct point;
point p2;
};
double z;
} threepoint;
double length (point p){
return sqrt(p.x*p.x + p.y*p.y);
}
double threelength (threepoint p){
return sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
}
int main(){
threepoint p = {.x=3, .y=0, .z=4};
printf("p is %g units from the origin\n", threelength(p));
double xylength = length(p.p2);
printf("Its projection onto the XY plane is %g units from the origin\n", xylength);
}
/* Suggested makefile:
----------
P=show_tree
objects=process_dir.o process_dir.h
CFLAGS= -g -Wall -O3
LDLIBS=
CC=c99
$(P): $(objects)
----------
*/
#include <stdio.h>
#include "process_dir.h"
void print_dir(filestruct in){
for (int i=0; i< in.depth-1; i++) printf(" ");
printf("├ %s\n", in.name);
for (int i=0; i< in.depth-1; i++) printf(" ");
printf("└───┐\n");
}
void print_file(filestruct in){
for (int i=0; i< in.depth; i++) printf(" ");
printf("│ %s\n", in.name);
}
int main(int argc, char **argv){
char *start = (argc>1) ? argv[1] : ".";
printf("Tree for %s:\n", start ? start: "the current directory");
process_dir(.name=start, .file_action=print_file, .directory_action=print_dir);
}
/* Suggested makefile:
----------
CFLAGS =-g -Wall -O3 `pkg-config --cflags gsl`
LDLIBS=`pkg-config --libs gsl`
CC=clang
simple_cplx: complex.o
----------
*/
#include <stdio.h>
#include "cplx.h"
int main(){
int complex a = 1+2I;
complex double b = 2+I;
gsl_complex c = gsl_cplx_from_c99(a);
gsl_vector *v = gsl_vector_alloc(8);
for (int i=0; i< v->size; i++) gsl_vector_set(v, i, i/8.);
complex double adotb = dot(a, b);
printf("(1+2i) dot (2+i): %g + %gi\n", creal(adotb), cimag(adotb));
printf("v dot 2:\n");
double d = 2;
gsl_vector_complex_print(dot(v, d));
printf("v dot (1+2i):\n");
gsl_vector_complex *vc = dot(v, a);
gsl_vector_complex_print(vc);
printf("v dot (1+2i) again:\n");
gsl_vector_complex_print(dot(v, c));
}
/* Compile with:
make sizesof CFLAGS="-g -Wall -std=gnu11 -O3"
*/
#include <stdio.h>
#define peval(cmd) printf(#cmd ": %g\n", cmd);
int main(){
double *plist = (double[]){1, 2, 3};
double list[] = {1, 2, 3};
peval(sizeof(plist)/(sizeof(double)+0.0));
peval(sizeof(list)/(sizeof(double)+0.0));
}
/* Compile with:
export LDLIBS="`pkg-config --libs gsl`"
export CFLAGS="`pkg-config --cflags gsl` -g -Wall -std=gnu11 -O3"
make stddev
*/
#include <math.h>
#include <stdio.h> //size_t
typedef struct meanvar {double mean, var;} meanvar;
meanvar mean_and_var(const double *data){
long double avg = 0,
avg2 = 0;
long double ratio;
size_t cnt= 0;
for(size_t i=0; !isnan(data[i]); i++){
ratio = cnt/(cnt+1.0);
cnt ++;
avg *= ratio;
avg2 *= ratio;
avg += data[i]/(cnt +0.0);
avg2 += pow(data[i], 2)/(cnt +0.0);
}
return (meanvar){.mean = avg,
.var = avg2 - pow(avg, 2)}; //E[x^2] - E^2[x]
}
int main(){
double d[] = { 34124.75, 34124.48,
34124.90, 34125.31,
34125.05, 34124.98, NAN};
meanvar mv = mean_and_var(d);
printf("mean: %.10g var: %.10g\n", mv.mean, mv.var*6/5.);
double d2[] = { 4.75, 4.48,
4.90, 5.31,
5.05, 4.98, NAN};
mv = mean_and_var(d2);
mv.var *= 6./5;
printf("mean: %.10g var: %.10g\n", mv.mean, mv.var);
}
#include <stdio.h>
#include <stdlib.h> //abort
/** Set this to \c 's' to stop the program on an error.
Otherwise, functions take error_action on failure.*/
char error_mode;
/** To where should I write errors? If this is \c NULL, write to \c stderr. */
FILE *error_log;
#define Stopif(assertion, error_action, ...) do { \
if (assertion){ \
fprintf(error_log ? error_log : stderr, __VA_ARGS__); \
fprintf(error_log ? error_log : stderr, "\n"); \
if (error_mode=='s') abort(); \
else {error_action;} \
} } while(0)
#include <glib.h>
#include <string.h>
#include "string_utilities.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h> //abort
char *string_from_file(char const *filename){
char *out;
GError *e=NULL;
GIOChannel *f = g_io_channel_new_file(filename, "r", &e);
if (!f) {
fprintf(stderr, "failed to open file '%s'.\n", filename);
return NULL;
}
if (g_io_channel_read_to_end(f, &out, NULL, &e) != G_IO_STATUS_NORMAL){
fprintf(stderr, "found file '%s' but couldn't read it.\n", filename);
return NULL;
}
return out;
}
ok_array *ok_array_new(char *instring, char const *delimiters){
ok_array *out= malloc(sizeof(ok_array));
*out = (ok_array){.base_string=instring};
char *scratch = NULL;
char *txt = strtok_r(instring, delimiters, &scratch);
if (!txt) return NULL;
while (txt) {
out->elements = realloc(out->elements, sizeof(char*)*++(out->length));
out->elements[out->length-1] = txt;
txt = strtok_r(NULL, delimiters, &scratch);
}
return out;
}
/* Frees the original string, because strtok_r mangled it, so it
isn't useful for any other purpose. */
void ok_array_free(ok_array *ok_in){
if (ok_in == NULL) return;
free(ok_in->base_string);
free(ok_in->elements);
free(ok_in);
}
#ifdef test_ok_array
int main (){
char *delimiters = " `~!@#$%^&*()_-+={[]}|\\;:\",<>./?\n";
ok_array *o = ok_array_new(strdup("Hello, reader. This is text."), delimiters);
assert(o->length==5);
assert(!strcmp(o->elements[1], "reader"));
assert(!strcmp(o->elements[4], "text"));
ok_array_free(o);
printf("OK.\n");
}
#endif
#include <string.h>
#define _GNU_SOURCE //asks stdio.h to include asprintf
#include <stdio.h>
//Safe asprintf macro
#define Sasprintf(write_to, ...) { \
char *tmp_string_for_extend = write_to; \
asprintf(&(write_to), __VA_ARGS__); \
free(tmp_string_for_extend); \
}
char *string_from_file(char const *filename);
typedef struct ok_array {
char **elements;
char *base_string;
int length;
} ok_array;
ok_array *ok_array_new(char *instring, char const *delimiters);
void ok_array_free(ok_array *ok_in);
#include "stopif.h"
#include <stdlib.h> //strtod
#include <math.h> //pow
int main(int argc, char **argv){
Stopif (argc < 2, return 1, "Give me a number on the command line to square.");
char *end;
double in = strtod(argv[1], &end);
Stopif(*end, return 2, "I couldn't parse '%s' to a number. "
"I had trouble with '%s'.", argv[1], end);
printf("The square of %g is %g\n", argv[1], pow(in, 2));
}
/* Compile with:
make sum_to_nan CFLAGS="-g -Wall -std=gnu11 -O3"
*/
#include <math.h> //NAN
#include <stdio.h>
double sum(double in[]){
double out=0;
for (int i=0; !isnan(in[i]); i++) out += in[i];
return out;
}
int main(){
double list[] = {1.1, 2.2, 3.3, NAN};
printf("sum: %g\n", sum(list));
printf("sum: %g\n", sum((double[]){1.1, 2.2, 3.3, NAN}));
}
#include <math.h> //NAN
#include <stdio.h>
#define make_a_list(...) (double[]){__VA_ARGS__, NAN}
#define matrix_cross(list1, list2) matrix_cross_base(make_a_list list1, make_a_list list2)
void matrix_cross_base(double *list1, double *list2){
int count1 = 0, count2 = 0;
while (!isnan(list1[count1])) count1++;
while (!isnan(list2[count2])) count2++;
if (!count1 || !count2) {printf("missing data."); return;}
for (int i=0; i<count1; i++){
for (int j=0; j<count2; j++)
printf("%g\t", list1[i]*list2[j]);
printf("\n");
}
printf("\n\n");
}
int main(){
matrix_cross((1,2,4,8), (5, 11.11, 15));
matrix_cross((17, 19, 23), (1,2,3,5,7,11,13));
matrix_cross((1,2,3,5,7,11,13), (1)); //a column vector
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make uint
*/
#include <stdio.h>
int main(){
int neg = -2;
size_t zero = 0;
if (neg < zero) printf("Yes, -2 is less than 0.\n");
else printf("No, -2 is not less than 0.\n");
}
/* Suggested makefile:
----------
P=unicode
objects=string_utilities.o
CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu11 -O3
LDLIBS=`pkg-config --libs glib-2.0`
$(P): $(objects)
----------
*/
/* Here is some sample UTF-8, so you can try this out.
If this looks like a mess, your browser may have an easier time displaying it, or try
iconv -f utf-8 -t UTF-16 < unicode.c > unicode.c.16
京冀洪涝灾情启动四级响应 #Today's headline from Chinadaily.com.
España, cercada por los mercados, prohíbe las operaciones especulativas #Today's headline from elpais.es.
3.141592653589793238462643383279 #pi.
*/
#include <glib.h>
#include <locale.h> //setlocale
#include "string_utilities.h"
#include "stopif.h"
//Frees instring for you--we can't use it for anything else.
char *localstring_to_utf8(char *instring){
GError *e=NULL;
setlocale(LC_ALL, ""); //get the OS's locale.
char *out = g_locale_to_utf8(instring, -1, NULL, NULL, &e);
free(instring); //done with the original
Stopif(!out, return NULL, "Trouble converting from your locale to UTF-8.");
Stopif(!g_utf8_validate(out, -1, NULL), free(out); return NULL,
"Trouble: I couldn't convert your file to a valid UTF-8 string.");
return out;
}
int main(int argc, char **argv){
Stopif(argc==1, return 1, "Please give a filename as an argument. "
"I will print useful info about it to uout.html.");
char *ucs = localstring_to_utf8(string_from_file(argv[1]));
Stopif(!ucs, return 1, "Exiting.");
FILE *out = fopen("uout.html", "w");
Stopif(!out, return 1, "Couldn't open uout.html for writing.");
fprintf(out, "<head><meta http-equiv=\"Content-Type\" "
"content=\"text/html; charset=UTF-8\" />\n");
fprintf(out, "This document has %li characters.<br>", g_utf8_strlen(ucs, -1));
fprintf(out, "Its Unicode encoding required %zu bytes.<br>", strlen(ucs));
fprintf(out, "Here it is, with each space-delimited element on a line "
"(with commentary on the first character):<br>");
ok_array *spaced = ok_array_new(ucs, " \n");
for (int i=0; i< spaced->length; i++, (spaced->elements)++){
fprintf(out, "%s", *spaced->elements);
gunichar c = g_utf8_get_char(*spaced->elements);
if (g_unichar_isalpha(c)) fprintf(out, " (a letter)");
if (g_unichar_isdigit(c)) fprintf(out, " (a digit)");
if (g_unichar_iswide(c)) fprintf(out, " (wide, CJK)");
fprintf(out, "<br>");
}
fclose(out);
printf("Info printed to uout.html. Have a look at it in your browser.\n");
}
/* See compilation notes in charct.c*/
#include "string_utilities.h"
#include "process_dir.h"
#include "unictr.h"
#include <glib.h>
#include <stdlib.h> //calloc, malloc
typedef struct {
int count;
} count_s;
void hash_a_character(gunichar uc, GHashTable *hash){
count_s *ct = g_hash_table_lookup(hash, &uc);
if (!ct){
ct = calloc(1, sizeof(count_s));
gunichar *newchar = malloc(sizeof(gunichar));
*newchar = uc;
g_hash_table_insert(hash, newchar, ct);
}
ct->count++;
}
void printone(void *key_in, void *val_in, void *ignored){
gunichar const *key= key_in;
count_s const *val= val_in;
char utf8[7];
utf8[g_unichar_to_utf8(*key, utf8)]='\0';
printf("%s\t%i\n", utf8, val->count);
}
static gboolean equal_chars(void const * a_in, void const * b_in){
const gunichar *a= a_in;
const gunichar *b= b_in;
return (*a==*b);
}
GHashTable *new_unicode_counting_hash(){
return g_hash_table_new(g_str_hash, equal_chars);
}
/* See compilation notes in charct.c*/
#include <glib.h>
void hash_a_character(gunichar uc, GHashTable *hash);
void printone(void *key_in, void *val_in, void *xx);
GHashTable *new_unicode_counting_hash();
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make varad
*/
#include <stdio.h>
#define forloop(i, loopmax, ...) for(int i=0; i< loopmax; i++) \
{__VA_ARGS__}
int main(){
int sum=0;
forloop(i, 10,
sum += i;
printf("sum to %i: %i\n", i, sum);
)
}
/* Compile with:
export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual.
make vectorize
*/
#include <stdio.h>
#include <stdlib.h> //malloc, free
#define Fn_apply(type, fn, ...) { \
void *stopper_for_apply = (int[]){0}; \
type **list_for_apply = (type*[]){__VA_ARGS__, stopper_for_apply}; \
for (int i=0; list_for_apply[i] != stopper_for_apply; i++) \
fn(list_for_apply[i]); \
}
#define Free_all(...) Fn_apply(void, free, __VA_ARGS__);
int main(){
double *x= malloc(10);
double *y= malloc(100);
double *z= malloc(1000);
Free_all(x, y, z);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册