SIPBs IAP Programming in C Pointers, and Arrays Memory and - - PowerPoint PPT Presentation

sipb s iap programming in c pointers and arrays memory
SMART_READER_LITE
LIVE PREVIEW

SIPBs IAP Programming in C Pointers, and Arrays Memory and - - PowerPoint PPT Presentation

SIPBs IAP Programming in C Pointers, and Arrays Memory and Addresses stack stack grows down - C programs exist inside a memory space (unmapped) - That memory space is a sequence of bytes heap grows heap up - Each of those bytes


slide-1
SLIDE 1

SIPB’s IAP Programming in C

slide-2
SLIDE 2

Pointers, and Arrays

slide-3
SLIDE 3

Memory and Addresses

  • C programs exist

inside a memory space

  • That memory space is

a sequence of bytes

  • Each of those bytes

has an address

stack (unmapped) heap bss text stack grows down heap grows up

slide-4
SLIDE 4

Addresses and Pointers

  • Addresses are usually

represented in hexadecimal

  • A pointer is a

variable, whose value is an address

  • A pointer has an

associated type, while an address does not

stack (unmapped) heap bss text 0x6f80a2e0 x int *xPtr = &x;

slide-5
SLIDE 5

Declaring a Pointer

  • Specify the type in the

normal way

  • Then, add an asterisk

for each layer of pointing

  • Pointers to pointers

are possible!

/* point to a 32-bit integer */ int *xPtr; /* point to a 32-bit float */ float *fPtr; /* point to an 8-bit integer */ char *cPtr; /* point to a point to an int */ int **xPtrPtr;

slide-6
SLIDE 6

Assigning a Pointer

  • Pointers have a type
  • And that type needs

to match up, during assignment

int x; int *xPtr; /* ... */ xPtr = &x;

slide-7
SLIDE 7

&

&varName returns address of varName Works for local & global variables, array elements, and struct members That address can then be stashed in a pointer

int is_square(int square, int *rootPtr) { /* ... */ } main() { int square,root; int *rootPtr; square = 25; rootPtr = &root; if(is_square(square,rootPtr)) printf("%d is square, with " "root %d\n", square,root); else printf("%d is NOT a square\n", square); }

slide-8
SLIDE 8

*

The asterisk derefer- ences a pointer:

  • *Ptr evaluates to

the value pointed to by Ptr

  • Works for both

right & left side of assignment

  • Can be nested

int is_square(int square, int *rootPtr) { int i; for(i=0;;i++) { int i2 = i * i; if(i2 == square) { if(rootPtr != NULL) *rootPtr = i; return(1); } else if(i2 > square) return(0); } }

slide-9
SLIDE 9

Asterisk vs. Ampersand

  • * is the inverse of &
  • But only to a limited

extent!

  • E.g. &*x is complete

hooey

int x,y; int *xPtr; x = 22; /* this: */ xPtr = &x; y = *xPtr; /* is the same as * this: */ y = *&x; /* is the same as * this: */ y = x;

slide-10
SLIDE 10

Multiple Pointers, Same Address

  • Multiple pointers can

provide access to the same underlying value

  • Just set them all to

the same address!

int x; int *xPtr,*yPtr; yPtr = xPtr = &x; *xPtr = 22; /* this will print: * *yPtr = 22 */ printf("*yPtr = %d\n", *yPtr);

slide-11
SLIDE 11

Call By Value

  • C’s calling convention

includes calling by value

  • The parameter values

are passed, not their address

  • Ergo, they are local to

the called function

/* the concept of futility, * expressed in C */ void swap(int a, int b) { int temp; temp = a; a = b; b = temp; }

slide-12
SLIDE 12

Call By Reference

  • You can explicitly call

by reference

  • Reference being

another way to say address

  • And addresses, that

means pointers

/* so much better */ void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; }

slide-13
SLIDE 13

Returning Values Via Pointers

  • Caller generates

pointers to local variables

  • Callee takes those

pointers as arguments

  • Callee writes values

through those pointers

  • On return, caller

finds local variables set to new values

  • And to the next

slide, for the example

slide-14
SLIDE 14

Just Like Magic

int is_square(int square, int *rootPtr) { int i; for(i=0;;i++) { int i2 = i * i; if(i2 == square) { if(rootPtr != NULL) *rootPtr = i; return(1); } else if(i2 > square) return(0); } } main() { int square,root; int *rootPtr; square = 25; rootPtr = &root; if(is_square(22,rootPtr)) printf("%d is a square, with " "root %d\n", square,root); else printf("%d is NOT a square\n", square); }

slide-15
SLIDE 15

Arrays

Array declarations are very similar to pointer declarations.

  • Array declarations
  • ften allocate the

underlying values

  • In those cases, the

array pointer will be initialized accordingly

/* these are identical */ int *xPtr; int xArr[]; /* this will allocate * memory for the array */ int *yPtr; int yArr[10]; /* totally valid */ yPtr = yArr;

slide-16
SLIDE 16

Pointer Arithmetic

  • Each pointer has a

type, from which its size can be derived

  • This size is used by

the compiler, when performing pointer arithmetic

  • Pointer arithmetic

and array indexing are identical

int *yPtr; int yArr[10]; yPtr = yArr; /* these are the same! */ yArr[3] = 1; *(yPtr + 3) = 1;

slide-17
SLIDE 17

Pointer arithmetic, and array indexing

Pointers are byte addresses (on most machines). Incrementing a char* pointer by one points it to the next byte. If the pointer type is larger, incrementing by

  • ne will change the

address by the number of bytes required to hold that type.

char int struct element 1 2 3 4 5 6 7 8 1 2 .x .y .c .x .y .c .x .y .c

slide-18
SLIDE 18

Arrays and Addresses

  • You can derive the

address of an array element

  • And not suprisingly,

this is closely related to pointer arithmetic

int *yPtr,*y3Ptr; int yArr[10]; yPtr = yArr; /* these are the same! */ y3Ptr = &yArr[3]; y3Ptr = yPtr + 3;

slide-19
SLIDE 19

sizeof()

The size of a given type

  • r variable is available

via the built-in function sizeof()

int *yPtr; int yArr[10]; /* what will this output * look like? */ printf("sizeof(int) = %d\n" "sizeof(yPtr) = %d\n" "sizeof(yArr) = %d\n", sizeof(int), sizeof(yPtr), sizeof(yArr));

slide-20
SLIDE 20
  • >

The arrow dereferences a pointer to a structure element

  • Simultaneous

structure member and pointer dereference

  • stPtr->x returns value
  • f field x, of the struct

pointed to by stPtr

struct MyStruct { int a; int b; }; main() { struct MyStruct m,*mPtr; m.a = 1; m.b = -1; mPtr = &m; printf("m.a = %d\n" "m.b = %d\n", mPtr->a, mPtr->b); }

slide-21
SLIDE 21

Strings Are Pointers

T h i s i s a s t r i n g \0

Strings are not special.

  • A "char *" is a pointer

to a block of memory

  • End of string is

indicated by ’\0’ character

  • Strings usually

manipulation via library routines

char *str = "This is a string";

slide-22
SLIDE 22

Strings Are Arrays

T h i s i s a s t r i n g \0

We can use array notation, when accessing strings.

int n = 1; char str[] = "This is a string"; printf("Character %d\n" "of ’%s’\n" "is ’%c’\n", n, str, str[n]); /* outputs: Character 1

  • f ’This is a string’

is ’h’ */

slide-23
SLIDE 23

String Layout

T h i s i s a s t r i n g \0

  • Strings are zero

indexed

  • I.e. the first character

is the zeroth

  • Strings are

terminated with ’\0’

int strlen(char *s) { int i; for(i=0;s[i] != ’\0’;i++) ; return(i); } main() { char *s = "This is a string"; printf("strlen(s) = %d\n", strlen(s)); } /* outputs: strlen(s) = 16 */

slide-24
SLIDE 24

Casting Between Pointers

  • A cast will force

conversion between types

  • A cast is a unary
  • perator
  • A cast is written as a

type, between parans

  • E.g. (int), (double),

(char *)

int *xPtr; char x[4]; xPtr = (int *)x; *xPtr = 22;

slide-25
SLIDE 25

Pointers and Longs

  • Pointers have a size,

which is architecture specific

  • This size is the native

word size

  • Longs are also native

words!

  • Longs and pointers

can be cast back and forth

  • Not that you want to

do that

int x, *xPtr; long p; xPtr = &x; p = (long)xPtr;

slide-26
SLIDE 26

Memory Allocation

  • Local variables

allocated on the stack

  • Most other

allocations are done

  • n the heap
  • Standard libc way:

malloc() and free()

void *malloc(int count); void free(void *alloc); main() { int *xPtr; xPtr = malloc(sizeof(int)); /* use xPtr here */ free(xPtr); }

slide-27
SLIDE 27

Heap Vs. Stack

  • Memory must be

allocated and freed

  • On the stack:

allocated and freed automatically in function scope

  • On the heap: allocated

and freed explicitly

  • Don’t expect these

allocations to be initialized

/* these variables are allocated * on the stack */ int i; int *xPtr; char str200[200]; /* this is allocated in * the heap */ xPtr = (int *)malloc(sizeof(int));

slide-28
SLIDE 28

The Heap Is All Crazy

  • A memory allocator

keeps track of which memory is in use

  • libc’s malloc is just

a memory allocator

  • Complex systems
  • ften have their
  • wn allocators
  • Convention: unused

memory is kept on a "freelist"

heap text (your code)

slide-29
SLIDE 29

Pointers are Power

  • There are no runtime

safety checks

  • You can read & write

memory anywhere the CPU can

  • Typical mistakes:

writing past end of allocated buffer, accessing previously freed memory, junk pointers

/* pointer casts like this can * really harsh the mellow */ *(int *)NULL = 22;

slide-30
SLIDE 30

And now, for a large example!

slide-31
SLIDE 31

image.c

slide-32
SLIDE 32

Remember PiC.c and PiC.h from the homework?

slide-33
SLIDE 33

/* * includes */ #include <stdlib.h> #include <stdio.h> #include "PiC.h" #include <string.h> int main(int argc, char *argv[]) { int i; char *my_name; my_name = argv[0]; for(i=1;i<argc;i++) { if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help")) { printf( "usage:\n" " %s [ options ]\n" "options:\n" " -h || --help this help message\n" my_name); exit(0); } else fprintf(stderr, "%s: unknown option ’%s’; use -h for help\n", my_name, argv[i]); } return(0); }

slide-34
SLIDE 34

First thing we need, is to pull in the header file

#include "PiC.h"

slide-35
SLIDE 35

In PiC.h, we define the necessary Image and Pixel structures

struct Pixel { unsigned char r; unsigned char g; unsigned char b; }; struct Image { unsigned int width; unsigned int height; struct Pixel *pixel; };

slide-36
SLIDE 36

We also add the ImagePixel() macro!

struct Image { unsigned int width; unsigned int height; struct Pixel *pixel; }; #define ImagePixel(i,x,y) \ ((i)->pixel[(x) + ((y) * (i)->width)])

slide-37
SLIDE 37

This will create an initialized copy of an Image structure

struct Pixel { unsigned char r; unsigned char g; unsigned char b; }; struct Image { unsigned int width; unsigned int height; struct Pixel *pixel; }; struct Image *PiC_image_create(unsigned int width, unsigned int height) { struct Image *img; if(!(img = (struct Image *) malloc(sizeof(struct Image))) || !(img->pixel = (struct Pixel *) malloc(sizeof(struct Pixel) * width * height))) { fprintf(stderr, "PiC_image_create: memory exhausted\n"); return(NULL); } img->width = width; img->height = height; return(img); }

slide-38
SLIDE 38

And this will destroy a copy of an Image structure

struct Pixel { unsigned char r; unsigned char g; unsigned char b; }; struct Image { unsigned int width; unsigned int height; struct Pixel *pixel; }; void PiC_image_destroy(struct Image *img) { free(img->pixel); free(img); }

slide-39
SLIDE 39

Finally, a function to set an image to one solid color

struct Pixel { unsigned char r; unsigned char g; unsigned char b; }; struct Image { unsigned int width; unsigned int height; struct Pixel *pixel; }; void PiC_image_set(struct Image *img, unsigned char r, unsigned char g, unsigned char b) { unsigned int x,y; struct Pixel pix; pix.r = r; pix.g = g; pix.b = b; for(x=0;x<img->width;x++) for(y=0;y<img->height;y++) ImagePixel(img,x,y) = pix; }

slide-40
SLIDE 40

These together constitute our

  • perations on Image

structures, and we put them in image.c

#include "PiC.h" struct Image *PiC_image_create(unsigned int width, unsigned int height) { struct Image *img; if(!(img = (struct Image *) malloc(sizeof(struct Image))) || !(img->pixel = (struct Pixel *) malloc(sizeof(struct Pixel) * width * height))) { fprintf(stderr, "PiC_image_create: memory exhausted\n"); return(NULL); } img->width = width; img->height = height; return(img); } void PiC_image_destroy(struct Image *img) { free(img->pixel); free(img); } void PiC_image_set(struct Image *img, unsigned char r, unsigned char g, unsigned char b) { unsigned int x,y; struct Pixel pix; pix.r = r; pix.g = g; pix.b = b; for(x=0;x<img->width;x++) for(y=0;y<img->height;y++) ImagePixel(img,x,y) = pix; }

slide-41
SLIDE 41

Now, we should go into PiC.h, and add prototypes for these functions we’ve just written

/* image.c */ struct Image *PiC_image_create(unsigned int, /* width */ unsigned int); /* height */ void PiC_image_destroy(struct Image *); /* image */ void PiC_image_set(struct Image *, /* image */ unsigned char, /* red */ unsigned char, /* green */ unsigned char); /* blue */

slide-42
SLIDE 42

Lets roll some changes into PiC.c

slide-43
SLIDE 43

#include "PiC.h" #include <string.h> int main(int argc, char *argv[]) { int i; int w=222,h=222; unsigned char r=200,g=50,b=200; char *my_name; struct Image *img; my_name = argv[0]; for(i=1;i<argc;i++) { if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help")) { printf( "usage:\n" " %s [ options ]\n" "options:\n" " -h || --help this help message\n" " -d || --dim <w> <h> sets image width and height\n" " to w and h\n" " -c || --color <r> <g> <b> sets the image background\n" " color\n", my_name); exit(0); } else if(!strcmp(argv[i],"-d") || !strcmp(argv[i],"--dim")) { w = atoi(argv[++i]); h = atoi(argv[++i]); } else if(!strcmp(argv[i],"-c") || !strcmp(argv[i],"--color")) { r = atoi(argv[++i]); g = atoi(argv[++i]); b = atoi(argv[++i]); } else fprintf(stderr, "%s: unknown option ’%s’; use -h for help\n", my_name, argv[i]); } img = PiC_image_create(w,h); PiC_image_set(img,r,g,b); PiC_image_destroy(img); return(0); }

slide-44
SLIDE 44

io.c

slide-45
SLIDE 45

Pull in the header file, and the system headers string.h and errno.h

#include "PiC.h" #include <string.h> #include <errno.h>

slide-46
SLIDE 46

This function will dump an Image structure to a file, in PPM format

void PiC_io_out(struct Image *img, char *filename) { FILE *file; int x,y; if(!(file = fopen(filename,"w"))) { fprintf(stderr, "PiC_io_out: unable to open ’%s’ for writing: %s\n", filename, strerror(errno)); return; } fprintf(file, "P6\n" "%d %d 255\n", img->width,img->height); for(y=0;y<img->height;y++) for(x=0;x<img->width;x++) fprintf(file, "%c%c%c", ImagePixel(img,x,y).r, ImagePixel(img,x,y).g, ImagePixel(img,x,y).b); fclose(file); }

slide-47
SLIDE 47

And then we update PiC.h with this prototype

/* io.c */ void PiC_io_out(struct Image *, /* image */ char *); /* filename */

slide-48
SLIDE 48

And lets update PiC.c with this new functionality...

slide-49
SLIDE 49

#include "PiC.h" #include <string.h> int main(int argc, char *argv[]) { int i; int w=222,h=222; unsigned char r=200,g=50,b=200; char *my_name,*out="PiC-image.ppm"; struct Image *img; my_name = argv[0]; for(i=1;i<argc;i++) { if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help")) { printf( "usage:\n" " %s [ options ]\n" "options:\n" " -h || --help this help message\n" " -d || --dim <w> <h> sets image width and height\n" " to w and h\n" " -c || --color <r> <g> <b> sets the image background\n" " color\n" " -o || --out <file> sets the output file name\n", my_name); exit(0); } else if(!strcmp(argv[i],"-d") || !strcmp(argv[i],"--dim")) { w = atoi(argv[++i]); h = atoi(argv[++i]); } else if(!strcmp(argv[i],"-c") || !strcmp(argv[i],"--color")) { r = atoi(argv[++i]); g = atoi(argv[++i]); b = atoi(argv[++i]); } else if(!strcmp(argv[i],"-o") || !strcmp(argv[i],"--out"))

  • ut = argv[++i];

else fprintf(stderr, "%s: unknown option ’%s’; use -h for help\n", my_name, argv[i]); } img = PiC_image_create(w,h); PiC_image_set(img,r,g,b); PiC_io_out(img,out); PiC_image_destroy(img); return(0); }

slide-50
SLIDE 50
  • mg fractals
slide-51
SLIDE 51
slide-52
SLIDE 52

Some trajectories escape the circle at radius 2...

slide-53
SLIDE 53

While others are sucked into the middle!

slide-54
SLIDE 54

But the interesting

  • nes are the ones that

can’t make up their mind.

slide-55
SLIDE 55

complex.c

slide-56
SLIDE 56

Pull in the header file

#include "PiC.h"

slide-57
SLIDE 57

In PiC.h, we define the Complex structure, and typedef it to PiCComplex

struct Complex { double r; double i; }; typedef struct Complex *PiCComplex_t;

slide-58
SLIDE 58

Make creators and destructors for type PiCComplex

struct Complex { double r; double i; }; typedef struct Complex *PiCComplex_t; PiCComplex_t PiC_complex_create(double r, double i) { PiCComplex_t c; if(!(c = (PiCComplex_t) malloc(sizeof(struct Complex)))) { fprintf(stderr, "PiC_complex_create: memory exhausted\n"); return(NULL); } c->r = r; c->i = i; return(c); } void PiC_complex_destroy(PiCComplex_t c) { free(c); }

slide-59
SLIDE 59

With these we can conveniently set a PiCComplex’s value, or copy it from another PiCComplex

struct Complex { double r; double i; }; typedef struct Complex *PiCComplex_t; PiCComplex_t PiC_complex_set(PiCComplex_t c, double r, double i) { if(!c) c = PiC_complex_create(r,i); else { c->r = r; c->i = i; } return(c); } PiCComplex_t PiC_complex_copy(PiCComplex_t c_dest, PiCComplex_t c_src) { if(!c_dest) c_dest = PiC_complex_create(c_src->r,c_src->i); else { c_dest->r = c_src->r; c_dest->i = c_src->i; } return(c_dest); }

slide-60
SLIDE 60

These provide us a flexible interface to necessary complex math

struct Complex { double r; double i; }; typedef struct Complex *PiCComplex_t; PiCComplex_t PiC_complex_add(PiCComplex_t c1, PiCComplex_t c2, PiCComplex_t c3) { if(!c3) c3 = PiC_complex_create(0,0); c3->r = c1->r + c2->r; c3->i = c1->i + c2->i; return(c3); } PiCComplex_t PiC_complex_mul(PiCComplex_t c1, PiCComplex_t c2, PiCComplex_t c3) { if(!c3) c3 = PiC_complex_create(0,0); c3->r = (c1->r * c2->r) - (c1->i * c2->i); c3->i = (c1->r * c2->i) + (c1->i * c2->r); return(c3); }

slide-61
SLIDE 61

And finally, the metric we’ll require for our fractal computations

struct Complex { double r; double i; }; typedef struct Complex *PiCComplex_t; double PiC_complex_size(PiCComplex_t c) { /* return((c->r * c->r) + (c->i * c->i)); */ /* This bogus size metric gives some nice * results; let’s use it instead */ return((c->r * c->r) - (c->i * c->i)); }

slide-62
SLIDE 62

Meanwhile, back PiC.h...

/* complex.c */ PiCComplex_t PiC_complex_create(double, /* real */ double); /* imaginary */ void PiC_complex_destroy(PiCComplex_t); /* complex */ PiCComplex_t PiC_complex_set(PiCComplex_t, /* dest */ double, /* real */ double); /* imaginary */ PiCComplex_t PiC_complex_copy(PiCComplex_t, /* dest */ PiCComplex_t); /* source */ PiCComplex_t PiC_complex_add(PiCComplex_t, /* c1 + */ PiCComplex_t, /* c2 -> */ PiCComplex_t); /* c3 */ PiCComplex_t PiC_complex_mul(PiCComplex_t, /* c1 * */ PiCComplex_t, /* c2 -> */ PiCComplex_t); /* c3 */ double PiC_complex_size(PiCComplex_t); /* complex */

slide-63
SLIDE 63

fractal.c

slide-64
SLIDE 64

As always, pull in the header file. Additionally, we’re going to be using variadic functions, so we bring in the system header file stdarg.h

#include "PiC.h" #include <stdarg.h>

slide-65
SLIDE 65

In PiC.h, we define the Fractal structure, and typedef it to PiCFractal_t

struct Fractal { struct Image *image; unsigned int julia_p:1; unsigned int red_p:1; unsigned int green_p:1; unsigned int blue_p:1; double r_min; double r_max; double i_min; double i_max; int itr_limit; struct Complex *julia_constant; }; typedef struct Fractal *PiCFractal_t;

slide-66
SLIDE 66

Also, we declare FractalParam as an enumerated type

enum FractalParam { JuliaP, RealLimit, ImaginaryLimit, ItrLimit };

slide-67
SLIDE 67

Notice: the Fractal structure contains a bunch of bitfields

unsigned int julia_p:1; unsigned int red_p:1; unsigned int green_p:1; unsigned int blue_p:1;

slide-68
SLIDE 68

The creator for type PiCFractal_t is more involved than our previous creators...

slide-69
SLIDE 69

struct Fractal { struct Image *image; unsigned int julia_p:1; unsigned int red_p:1; unsigned int green_p:1; unsigned int blue_p:1; double r_min; double r_max; double i_min; double i_max; int itr_limit; struct Complex *julia_constant; }; typedef struct Fractal *PiCFractal_t; enum FractalParam { JuliaP, RealLimit, ImaginaryLimit, ItrLimit }; PiCFractal_t PiC_fractal_create(struct Image *img, int param_count, ...) { int i; PiCFractal_t fr; va_list list; if(!(fr = (PiCFractal_t) malloc(sizeof(struct Fractal)))) { fprintf(stderr, "PiC_fractal_create: memory exhausted\n"); return(NULL); } fr->image = img; fr->julia_p = 0; fr->r_min = -2; fr->r_max = 1; fr->i_min = -1; fr->i_max = 1; fr->itr_limit = 20; fr->julia_constant = PiC_complex_create(0,0); va_start(list,param_count); for(i=0;i<param_count;i++) { enum FractalParam param; param = va_arg(list,enum FractalParam); switch(param) { case JuliaP: fr->julia_p = va_arg(list,unsigned int); if(fr->julia_p) { double r,i; r = va_arg(list,double); i = va_arg(list,double); PiC_complex_set(fr->julia_constant,r,i); } break; case RealLimit: fr->r_min = va_arg(list,double); fr->r_max = va_arg(list,double); break; case ImaginaryLimit: fr->i_min = va_arg(list,double); fr->i_max = va_arg(list,double); break; case ItrLimit: fr->itr_limit = va_arg(list,unsigned int); break; default: fprintf(stderr, "PiC_fractal_create: unknown param %d\n", (int)param); } } va_end(list); return(fr); }

slide-70
SLIDE 70

But the destructor remains simple

struct Fractal { struct Image *image; unsigned int julia_p:1; unsigned int red_p:1; unsigned int green_p:1; unsigned int blue_p:1; double r_min; double r_max; double i_min; double i_max; int itr_limit; struct Complex *julia_constant; }; typedef struct Fractal *PiCFractal_t; void PiC_fractal_destroy(PiCFractal_t fr) { PiC_complex_destroy(fr->julia_constant); free(fr); }

slide-71
SLIDE 71

Rendering the fractal is mostly an exercise in translating between the fractal coordinate system, and the coordinate system of the image

struct Fractal { struct Image *image; unsigned int julia_p:1; unsigned int red_p:1; unsigned int green_p:1; unsigned int blue_p:1; double r_min; double r_max; double i_min; double i_max; int itr_limit; struct Complex *julia_constant; }; typedef struct Fractal *PiCFractal_t; void PiC_fractal_render(PiCFractal_t fr) { int x,y; double r_span,i_span; r_span = fr->r_max - fr->r_min; i_span = fr->i_max - fr->i_min; for(x=0;x<fr->image->width;x++) for(y=0;y<fr->image->height;y++) { double r,i,d; r = fr->r_min + (r_span * ((double)x / (double)(fr->image->width - 1))); i = fr->i_min + (i_span * ((double)y / (double)(fr->image->height - 1))); d = fractal_eval(fr,r,i); ImagePixel(fr->image,x,y).r = (1-d) * 255; ImagePixel(fr->image,x,y).g = d * 255; ImagePixel(fr->image,x,y).b = (1-d) * 255; } }

slide-72
SLIDE 72

Then, fractal_eval() does the heavy lifting

slide-73
SLIDE 73

struct Fractal { struct Image *image; unsigned int julia_p:1; unsigned int red_p:1; unsigned int green_p:1; unsigned int blue_p:1; double r_min; double r_max; double i_min; double i_max; int itr_limit; struct Complex *julia_constant; }; typedef struct Fractal *PiCFractal_t; static double fractal_eval(PiCFractal_t fr, double r, double i) { int k; PiCComplex_t a_new,a_old,ic; /* create and initialize our values */ if(fr->julia_p) ic = PiC_complex_copy(NULL,fr->julia_constant); else ic = PiC_complex_set(NULL,r,i); a_new = PiC_complex_set(NULL,0,0); a_old = PiC_complex_set(NULL,r,i); /* iterate the map on this point, to * determine its ultimate trajectory */ for(k=0;k<fr->itr_limit;k++) { /* a_new = a_old^2 + ic */ PiC_complex_mul(a_old,a_old,a_new); PiC_complex_add(a_new,ic,a_new); if(PiC_complex_size(a_new) > 4) break; PiC_complex_copy(a_old,a_new); } /* we created these complex numbers; now we * must destroy them */ PiC_complex_destroy(a_new); PiC_complex_destroy(a_old); PiC_complex_destroy(ic); /* the return value is a measure of how long * it took to get where it was going */ return(1 - ((double)k / (double)fr->itr_limit)); }

slide-74
SLIDE 74

And then, we should add function prototypes into PiC.h

/* fractal.c */ PiCFractal_t PiC_fractal_create(struct Image *, /* image */ int, /* param cnt */ ...); /* params */ void PiC_fractal_destroy(PiCFractal_t); /* fractal */ void PiC_fractal_render(PiCFractal_t); /* fractal */

slide-75
SLIDE 75

Finally, we need to update PiC.c to support this new functionality...

slide-76
SLIDE 76

#include "PiC.h" #include <string.h> int main(int argc, char *argv[]) { int i; int w=222,h=222; int itr_limit=12; double r_min=-2,r_max=.7,i_min=-1.35,i_max=1.35; char *my_name,*out="PiC-image.ppm"; struct Image *img; PiCFractal_t fr; my_name = argv[0]; for(i=1;i<argc;i++) { if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help")) { printf( "usage:\n" " %s [ options ]\n" "options:\n" " -h || --help this help message\n" " -d || --dim <w> <h> sets image width and height\n" " to w and h\n" " -o || --out <file> sets the output file name\n" " -r || --real <min> <max> set the real value range\n" " -i || --imag <min> <max> set the imaginary value range\n" " -t || --itr <max> set the iteration limit\n", my_name); exit(0); } else if(!strcmp(argv[i],"-d") || !strcmp(argv[i],"--dim")) { w = atoi(argv[++i]); h = atoi(argv[++i]); } else if(!strcmp(argv[i],"-o") || !strcmp(argv[i],"--out"))

  • ut = argv[++i];

else if(!strcmp(argv[i],"-r") || !strcmp(argv[i],"--real")) { r_min = atof(argv[++i]); r_max = atof(argv[++i]); } else if(!strcmp(argv[i],"-i") || !strcmp(argv[i],"--imag")) { i_min = atof(argv[++i]); i_max = atof(argv[++i]); } else if(!strcmp(argv[i],"-t") || !strcmp(argv[i],"--itr")) itr_limit = atoi(argv[++i]); else fprintf(stderr, "%s: unknown option ’%s’; use -h for help\n", my_name, argv[i]); } img = PiC_image_create(w,h); fr = PiC_fractal_create(img,3, RealLimit,r_min,r_max, ImaginaryLimit,i_min,i_max, ItrLimit,itr_limit); PiC_fractal_render(fr); PiC_io_out(img,out); PiC_fractal_destroy(fr); PiC_image_destroy(img); return(0); }

slide-77
SLIDE 77