SIPBs IAP Programming in C Pointers, and Arrays Memory and - - PowerPoint PPT Presentation
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
Pointers, and Arrays
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
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;
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;
Assigning a Pointer
- Pointers have a type
- And that type needs
to match up, during assignment
int x; int *xPtr; /* ... */ xPtr = &x;
&
&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); }
*
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); } }
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;
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);
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; }
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; }
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
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); }
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;
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;
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
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;
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));
- >
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); }
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";
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’ */
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 */
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;
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;
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); }
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));
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)
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;
And now, for a large example!
image.c
Remember PiC.c and PiC.h from the homework?
/* * 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); }
First thing we need, is to pull in the header file
#include "PiC.h"
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; };
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)])
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); }
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); }
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; }
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; }
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 */
Lets roll some changes into PiC.c
#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); }
io.c
Pull in the header file, and the system headers string.h and errno.h
#include "PiC.h" #include <string.h> #include <errno.h>
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); }
And then we update PiC.h with this prototype
/* io.c */ void PiC_io_out(struct Image *, /* image */ char *); /* filename */
And lets update PiC.c with this new functionality...
#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); }
- mg fractals
Some trajectories escape the circle at radius 2...
While others are sucked into the middle!
But the interesting
- nes are the ones that
can’t make up their mind.
complex.c
Pull in the header file
#include "PiC.h"
In PiC.h, we define the Complex structure, and typedef it to PiCComplex
struct Complex { double r; double i; }; typedef struct Complex *PiCComplex_t;
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); }
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); }
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); }
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)); }
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 */
fractal.c
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>
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;
Also, we declare FractalParam as an enumerated type
enum FractalParam { JuliaP, RealLimit, ImaginaryLimit, ItrLimit };
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;
The creator for type PiCFractal_t is more involved than our previous creators...
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); }
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); }
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; } }
Then, fractal_eval() does the heavy lifting
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)); }
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 */
Finally, we need to update PiC.c to support this new functionality...
#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); }