#include <stdio.h> int main() { int x = 5; int y = 7; int z = 25; printf("The value of x is %2d and it is stored at address %p\n",x,&x); printf("The value of y is %2d and it is stored at address %p\n",y,&y); printf("The value of z is %2d and it is stored at address %p\n",z,&z); return 0; }In produces the following output on one of our systems:
The value of x is 5 and it is stored at address ffbef1f8 The value of y is 7 and it is stored at address ffbef1f4 The value of z is 25 and it is stored at address ffbef1f0The results may be different on different systems and you may get different values each time you run the program.
On our system, addresses are represented in hexadecimal (base 16) and you will notice that the addresses differ by 4.
Also notice that z is stored first.
This may be unexpected, but remember that you cannot assume anything about what addresses will be used for variables.
Arrays Arrays are stored in consecutive memory cells.
#include <stdio.h> int main() { char a[10]; int i; for (i=0;i<10;i++) a[i] = 'A' + i; printf("The address of the array is %p\n",a); printf("The value stored at index 5 is %c and its address is %p\n", a[5],&a[5]); return 0; }
The address of the array is ffbef1f2 The value stored at index 5 is F and its address is ffbef1f7Notice that the address of a[5] is 5 more than the address of a
#include <stdio.h> int main() { int x[10]; int i; for (i=0;i<10;i++) x[i] = i; printf("The address of the array is %p\n",x); printf("The value stored at index 5 is %c and its address is %p\n", x[5],&x[5]); return 0; }We get the following:
The address of the array is ffbef1d4 The value stored at index 5 is and its address is ffbef1e8In base 16, e8 is 20 more than d4
Example:
#include <stdio.h> int main() { int x = 1; int y; int z[10]; int *ip; z[0] = 100; z[1] = 101; z[2] = 102; ip = &x; y = *ip; *ip = 0; ip = &z[0]; *ip = 5; printf("z[0] now %d\n",z[0]); ++*ip; printf("z[0] now %d\n",z[0]); (*ip)++; printf("z[0] now %d\n",z[0]); printf("This thing is %d\n",*ip++); printf("ip now points to %d\n",*ip); return 0; }
z[0] now 5 z[0] now 6 z[0] now 7 This thing is 7 ip now points to 101
|
Consider a program whose memory is shown at the left. We assume 4 bytes per integer and that only integers are stored in memory. Here is a piece of the program. int x; x = 5; printf("x = %d\n",x); increment(x); printf("x = %d\n",x); ... void increment(int x) { x++; }What does the output look like? Suppose that x is stored at location 1004 and the increment function uses location 1036 for its storage of its parameter. What does the memory look like after the call? Now consider the following: int x; x = 5; printf("x = %d\n",x); increment1(&x); printf("x = %d\n",x); ... void increment1(int *x) { (*x)++; }Now what is the output and what does the memory look like assuming increment1 uses location 1032 for its parameter? |
Recall that an array name is a pointer to the start of the array.
Consider the following function:
void fillArray(int a[], int size) { int i; for (i=0;i<size;i++) a[i] = i*i; }This works because the address of the array is being passed to the function.
Answer: space for one pointer (a) and two integers (size,i).
Consider the following calling program with the memory given above.
int main() { int a[5]; int size = 5; fillArray(a,size); }Assume that a starts at location 1008 and that size is stored in location 1004.
The following does not work:
#include <stdio.h> void swap(int x, int y) { int temp; temp = x; x = y; y = temp; } int main() { int a = 2; int b = 3; printf("a = %d and b = %d\n",a,b); swap(a,b); printf("a = %d and b = %d\n",a,b); return 0; }What is the output generated?
The following does work:
#include <stdio.h> void swap(int *px, int *py) { int temp; temp = *px; *px = *py; *py = temp; } int main() { int a = 2; int b = 3; printf("a = %d and b = %d\n",a,b); swap(&a,&b); printf("a = %d and b = %d\n",a,b); return 0; }
Consider the following:
int a[10]; int *pa; pa = a;The last line could also have been written pa = &a[0];.
Similarities between the a and pa.
About programming Assignment 0:
comments
addposint
subposint
You can add an integer to a pointer to get another pointer.
pa + n means the same thing as &(pa[n]).
Note that pa+1 is not one more than pa unless pa points to a char.
Adding 1 to a pointer causes it to point to the next value.
You can do the same with a:
*(a+i) means the same thing as a[i].
Since pa is a variable, and you can add one to it, pa++ makes sense.
However, a is not a variable (it is a constant pointer) and so you cannot do a++.
When used as a formal parameter to a function, the declarations
char *a and char a[] are equivalent.
In the latter, a is not treated as a constant.
Here are two versions of strlen which are equivalent:
int strlen(char s[]) { int n; for (n=0; *s != '\0'; s++) n++; return n; } int strlen(char *s) { int n; for (n=0; *s != '\0'; s++) n++; return n; }Note that even in the first of these, s is not considered a constant.
If a pointer (or an array) is passed to either of these, the value in the calling function is not changed.
|
Consider a program whose memory is shown at the left. We assume 4 bytes per integer or pointer. Here is a piece of a program. Assume that the main program stores the array a starting at location 1004 and that it uses 1000 to store i. Assume that strlen stores its parameter at 1024 and n at 1028. int strlen(char s[]) { int n; for (n=0; *s != '\0'; s++) n++; return n; } int main() { char a[4]; int i; for (i=0;i<3;i++) a[i] = 'A'+i; a[3] = '\0'; i = strlen(a) printf("The length is %d\n",i); }Tricky question: at what location is the value of a stored? |
Instead we will look at the library routines for doing memory allocation.
First, here are some the the key ideas that are used in this section
of the text.
Assume that p and q are pointer variables which have been
initialized to point to elements of the same array.
Memory Allocation
Problem: Write a function that reads a line from standard input and returns
a string containing that line.
This sounds a lot like the getline that we discussed earlier.
int getline(char line[], int maxline);
However, this function was given an array of a fixed size and stored the line in this array.
It could not handle the case of a line larger than the array.
We would like a function that will create and array of the appropriate size and return a pointer to it to the calling function.
What is wrong with the following?
(The problem is not just he maximum line size.)
#define MAXLINE 1000 char *getLine() { char a[MAXLINE]; getline(a,MAXLINE); return a; }
Exam seating:
Every other seat starting at the ends of each row
First few rows reserved for overflow
Warning: Programming Assignment 1 makefile
make clean
will remove heaptester.o
because it does:
rm -f heaptest heaptester *.o
I put out a new makefile which instead does:
mv heaptester.o heaptester.oo rm -f heaptest heaptester *.o mv heaptester.oo heaptester.o
malloc
#include <stdlib.h> void *malloc(size_t size);
#define MAXLINE 1000 char *getLine() { char *p; p = (char *)malloc(MAXLINE); if (p == NULL) return p; getline(p,MAXLINE); return p; }
Idea: allocate some space and start reading characters. If you run out of space, allocate more.
We can free up space that was created with malloc using free.
#include <stdlib.h> void free(void *ptr);ptr must have been returned by a previous malloc (or related function).
#include <stdio.h> #include <stdlib.h> #define INIT_ALLOC 100 char *getLine() { int currentAlloc; int spaceLeft; char *line; char *templine; char *next; int c; currentAlloc = INIT_ALLOC; spaceLeft = currentAlloc; line = (char *)malloc(currentAlloc); if (line == NULL) return line; next = line; while ((c=getchar()) != '\n') { if (c == EOF) { *next = '\0'; return line; } if (spaceLeft < ???) { /* always leave room for some more */ /* reallocate here */ } *next = c; next++; spaceLeft--; } *next = '\n'; next++; *next = '\0'; return line; }
No Lab assignement due this week.
Lab Assignment 3 due Thursday, March 1: (along with Programming assignment 1)
Rewrite the allocation code below using realloc.
Here is what we added in class on Feb 15:
if (spaceList == 2) { templine = (char *)malloc(2*currentAlloc); if (templine == NULL) { free(line); return NULL; } for (i=0;i<currentAlloc-2;i++) templine[i] = line[i]; free(line); line = templine; spaceleft += currentAlloc; next = line + currentAlloc - 2; currentAlloc *= 2; }
Other forms of malloc
void *calloc(size_2 nelem, size_t elsize);
This allocates space for an array of nelem elements of size
elsize.
The space is initialized to all zeros.
Note that space created by maloc is not initialized.
void *realloc(void *ptr, size_t size);
This changes the size of the block pointed to by ptr
to size bytes and returns a pointer to the
(possibly moved) block.
The contents will be unchanged up to the lesser of
the new and old sizes.
If ptr is NULL, realloc() behaves like malloc() for the specified size.
If size is zero and ptr is not a null pointer,
the object pointed to is freed.
Problem: Write a filter to ...
Many filters deal with lines and must read in the entire line before processing
it.
The filter must be able to handle arbitrarily long lines.
What is wrong with using the getLine we just wrote?
Replace with:
char *getLine(char *line, int size);
Like the one we just wrote, but uses line for the initial storage,
unless it is NULL.
What is wrong with this and how can we fix it?
There is also a difference between the ways these are stored:
Here are several examples of a string copy function:
void strcpy(char s[], char t[]) { int i; i = 0; while ( t[i] != '\0' ) { s[i] = t[i]; i++; } s[i] = '\0'; } void strcpy(char s[], char t[]) { int i; i = 0; while ( (s[i] = t[i]) != '\0' ) i++; } void strcpy(char *s, char *t) { int i; i = 0; while ( (*(s+i) = *(t+i)) != '\0' ) i++; } void strcpy(char *s, char *t) { while ( (*s = *t) != '\0' ) { s++; t++; } } void strcpy(char *s, char *t) { while ( (*s++ = *t++) != '\0' ) ; } void strcpy(char *s, char *t) { while (*s++ = *t++) ; }There is a version of strcpy in the standard library and declared in string.h. This version returns the target string.
Another basic string function is strcmp which compares two strings.
int strcmp(char *s, char *t);Here is the man page description:
int strcmp(const char *s1, const char *s2);
Here is an array implementation:
int strcmp(char *s, char *t) { int i; for (i=0; s[i] == t[i]; i++) if (s[i] == '\0') return 0; return s[i] - t[i]; }Here is a pointer version:
int strcmp(char *s, char *t) { for ( ; *s == *t; s++, t++) if (*s == '\0') return 0; return *s - *t; }
#define MAXLINES 100 char *lineptr[MAXLINES];Let us write a sorting routine to sort an array of strings.
We will prepare by sorting an array of integers:
void bubblesortint(int vals[], int size) { int i; int j; int temp; for (i=0;i<size-1;i++) for (j=0;j<size-i-1;j++) if (vals[j] > vals[j+1]) { temp = vals[j]; vals[j] = vals[j+1]; vals[j+1] = temp; } }Suppose that bubblesortint stores its parameters at 1000 and 1004 and its other automatic variables at 1008, 1012, and 1016. Assume the memory looks like this just after the function has been called:
address | value | address | value | |
1000 | 2000 | 2000 | 20 | |
1004 | 5 | 2004 | 17 | |
1008 | 102 | 2008 | 34 | |
1012 | 103 | 2012 | 11 | |
1016 | 104 | 2016 | 7 |
The values to be sorted: |
|
After first pass:
address | value | address | value | |
1000 | 2000 | 2000 | 17 | |
1004 | 5 | 2004 | 20 | |
1008 | 1 | 2008 | 11 | |
1012 | 4 | 2012 | 7 | |
1016 | 34 | 2016 | 34 |
The values to be sorted: |
|
After second pass:
address | value | address | value | |
1000 | 2000 | 2000 | 17 | |
1004 | 5 | 2004 | 11 | |
1008 | 2 | 2008 | 7 | |
1012 | 3 | 2012 | 20 | |
1016 | 20 | 2016 | 34 |
The values to be sorted: |
|
After third pass:
address | value | address | value | |
1000 | 2000 | 2000 | 11 | |
1004 | 5 | 2004 | 7 | |
1008 | 3 | 2008 | 17 | |
1012 | 2 | 2012 | 20 | |
1016 | 17 | 2016 | 34 |
The values to be sorted: |
|
After fourth pass:
address | value | address | value | |
1000 | 2000 | 2000 | 7 | |
1004 | 5 | 2004 | 11 | |
1008 | 3 | 2008 | 17 | |
1012 | 1 | 2012 | 20 | |
1016 | 11 | 2016 | 34 |
The values to be sorted: |
|
Now we will do a sort using pointers to integers:
void bubblesortintpointer(int *vals[], int size) { int i; int j; int temp; for (i=0;i<size-1;i++) for (j=0;j<size-i-1;j++) if (*vals[j] > *vals[j+1]) { temp = *vals[j]; *vals[j] = *vals[j+1]; *vals[j+1] = temp; } }Suppose that bubblesortintpointer stores its parameters at 1000 and 1004 and its other automatic variables at 1008, 1012, and 1016. Assume the memory looks like this just after the function has been called:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2012 | 2000 | 34 | ||
1004 | 5 | 1504 | 2008 | 2004 | 7 | ||
1008 | 102 | 1508 | 2000 | 2008 | 17 | ||
1012 | 103 | 1512 | 2016 | 2012 | 20 | ||
1016 | 104 | 1516 | 2004 | 2016 | 11 |
The values to be sorted: |
|
After the first pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2012 | 2000 | 11 | ||
1004 | 5 | 1504 | 2008 | 2004 | 34 | ||
1008 | 1 | 1508 | 2000 | 2008 | 20 | ||
1012 | 4 | 1512 | 2016 | 2012 | 17 | ||
1016 | 34 | 1516 | 2004 | 2016 | 7 |
The values to be sorted: |
|
After the second pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2012 | 2000 | 7 | ||
1004 | 5 | 1504 | 2008 | 2004 | 34 | ||
1008 | 2 | 1508 | 2000 | 2008 | 11 | ||
1012 | 3 | 1512 | 2016 | 2012 | 17 | ||
1016 | 20 | 1516 | 2004 | 2016 | 20 |
The values to be sorted: |
|
After the third pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2012 | 2000 | 17 | ||
1004 | 5 | 1504 | 2008 | 2004 | 34 | ||
1008 | 3 | 1508 | 2000 | 2008 | 7 | ||
1012 | 4 | 1512 | 2016 | 2012 | 11 | ||
1016 | 17 | 1516 | 2004 | 2016 | 20 |
The values to be sorted: |
|
After the fourth pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2012 | 2000 | 17 | ||
1004 | 5 | 1504 | 2008 | 2004 | 34 | ||
1008 | 4 | 1508 | 2000 | 2008 | 11 | ||
1012 | 5 | 1512 | 2016 | 2012 | 7 | ||
1016 | 11 | 1516 | 2004 | 2016 | 20 |
The values to be sorted: |
|
Now we will look at a different way of sorting the array with pointers:
void bubblesortintpointerpointer(int *vals[], int size) { int i; int j; int *temp; for (i=0;i<size-1;i++) for (j=0;j<size-i-1;j++) if (*vals[j] > *vals[j+1]) { temp = vals[j]; vals[j] = vals[j+1]; vals[j+1] = temp; } }Instead of sorting the values stored at 2000 we sort the pointers stored at 1500.
Suppose that bubblesortintpointerpointer stores its parameters at 1000 and 1004
and its other automatic variables at 1008, 1012, and 1016. Assume
the memory looks like this just after the function has been called:
Note: This is exactly the same as in the previous example.
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2012 | 2000 | 34 | ||
1004 | 5 | 1504 | 2008 | 2004 | 7 | ||
1008 | 102 | 1508 | 2000 | 2008 | 17 | ||
1012 | 103 | 1512 | 2016 | 2012 | 20 | ||
1016 | 104 | 1516 | 2004 | 2016 | 11 |
The values to be sorted: |
|
After the first pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2008 | 2000 | 34 | ||
1004 | 5 | 1504 | 2012 | 2004 | 7 | ||
1008 | 1 | 1508 | 2016 | 2008 | 17 | ||
1012 | 4 | 1512 | 2004 | 2012 | 20 | ||
1016 | 2000 | 1516 | 2000 | 2016 | 11 |
The values to be sorted: |
|
After the second pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2008 | 2000 | 34 | ||
1004 | 5 | 1504 | 2016 | 2004 | 7 | ||
1008 | 2 | 1508 | 2004 | 2008 | 17 | ||
1012 | 3 | 1512 | 2012 | 2012 | 20 | ||
1016 | 2012 | 1516 | 2000 | 2016 | 11 |
The values to be sorted: |
|
After the third pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2016 | 2000 | 34 | ||
1004 | 5 | 1504 | 2004 | 2004 | 7 | ||
1008 | 3 | 1508 | 2008 | 2008 | 17 | ||
1012 | 2 | 1512 | 2012 | 2012 | 20 | ||
1016 | 2008 | 1516 | 2000 | 2016 | 11 |
The values to be sorted: |
|
After the fourth pass it looks like this:
address | value | address | value | address | value | ||
1000 | 1500 | 1500 | 2004 | 2000 | 34 | ||
1004 | 5 | 1504 | 2016 | 2004 | 7 | ||
1008 | 4 | 1508 | 2008 | 2008 | 17 | ||
1012 | 1 | 1512 | 2012 | 2012 | 20 | ||
1016 | 2016 | 1516 | 2000 | 2016 | 11 |
The values to be sorted: |
|
What is the advantage of the third method over the second?
If integers and pointers are the same size, there is no advantage.
What if the integers were 8 bytes or 16 bytes or 16,000 bytes?
Here is the third sort applied to doubles:
void bubblesortdoublepointerpointer(double *vals[], int size) { int i; int j; double *temp; for (i=0;i<size-1;i++) for (j=0;j<size-i-1;j++) if (*vals[j] > *vals[j+1]) { temp = vals[j]; vals[j] = vals[j+1]; vals[j+1] = temp; } }
What is wrong with the following to convert it to strings:
void bubblesortcharpointerpointer(char *vals[], int size) { int i; int j; char *temp; for (i=0;i<size-1;i++) for (j=0;j<size-i-1;j++) if (*vals[j] > *vals[j+1]) { temp = vals[j]; vals[j] = vals[j+1]; vals[j+1] = temp; } }
Here is the right way:
#include <string.h> void bubblesortstringpointerpointer(char *vals[], int size) { int i; int j; char *temp; for (i=0;i<size-1;i++) for (j=0;j<size-i-1;j++) if (strcmp(vals[j],vals[j+1]) > 0) { temp = vals[j]; vals[j] = vals[j+1]; vals[j+1] = temp; } }
C does not have multi-dimensional arrays.
This should be familiar because Java does not either.
What these both have are arrays whose elements are arrays, and these behave like 2-dimensional arrays.
Here is an example from the book that can be used to calculate the number of days in a month:
int daytab[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, };Note that January has index 1, not 0.
The array is stored by rows, so the first row is stored in memory followed by the second row.
If integers take up 4 bytes and the array starts at location 1000, then
daytab[0][0] is stored in locations 1000-1003 and daytab[0][1]
is stored in locations 1004-1007.
daytab[1][0] is stored in locations 1052-1055.
Elements of 2-dimensional arrays are accessed with two pairs of brackets:
x = daytab[1][10];
The following is incorrect:
x = daytab[1,10];
How does the C compiler calculate the address of daytab[a][b]:
daytab + sizeof(int)*(13*a + b)Note that the compiler needs to know the number of columns, but not the number of rows.
What you write a function which takes this 2-dimensional array as a parameter.
you could do its definition as
f(int daytab[2][13]) { ...
or
f(int daytab[][13]) { ...
but not
f(int daytab[][]) { ...
char *month_name(int n) { static char *name[] = { "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return ( n<1 || n>12 ) ? name[0] : name[n]; }What does the static do?
#include <stdio.h> int main() { char *name_pointer[] = { "Illegal month", "Jan.", "Feb." }; char name_array[][13] = { {"Illegal month"},{"Jan."},{"Feb."} }; printf("name_pointer[0] is %s\n",name_pointer[0]); printf("name_pointer[1] is %s\n",name_pointer[1]); printf("name_pointer[2] is %s\n",name_pointer[2]); printf("name_pointer[0] is stored at %p\n",&(name_pointer[0])); printf("name_pointer[1] is stored at %p\n",&(name_pointer[1])); printf("name_pointer[2] is stored at %p\n",&(name_pointer[2])); printf("name_pointer[0] points to %p\n",name_pointer[0]); printf("name_pointer[1] points to %p\n",name_pointer[1]); printf("name_pointer[2] points to %p\n",name_pointer[2]); printf("\n"); printf("name_array[0] is %s\n",name_array[0]); printf("name_array[1] is %s\n",name_array[1]); printf("name_array[2] is %s\n",name_array[2]); printf("name_array[0] is stored at %p\n",name_array[0]); printf("name_array[1] is stored at %p\n",name_array[1]); printf("name_array[2] is stored at %p\n",name_array[2]); return 0; }Here is the output generated by this program:
name_pointer[0] is Illegal month name_pointer[1] is Jan. name_pointer[2] is Feb. name_pointer[0] is stored at effffa20 name_pointer[1] is stored at effffa24 name_pointer[2] is stored at effffa28 name_pointer[0] points to 20db8 name_pointer[1] points to 20dc8 name_pointer[2] points to 20dd0 name_array[0] is Illegal monthJan. name_array[1] is Jan. name_array[2] is Feb. name_array[0] is stored at effff9f9 name_array[1] is stored at effffa06 name_array[2] is stored at effffa13
You can practice writing some of the string functions from the standard library. Their descriptions can be found here and here.
What is passed is an array of pointers to characters and the length of the array.
The prototype for this is:
int main(int argc, char *argv[]);
Recall that when you specify and array as a function argument, what is passed is not a constant, but a variable containing the address of the array.
Suppose a program named echo is called with:
echo hello worldThen the arguments would look like this:
Here is a program that will echo its command line arguments, one per line:
int main(int argc, char *argv[]) { int i; for (i=1;i<argc; i++) printf("%s\n",argv[i]); return 0; }Note that i starts at 1 so we do not output the name of the program.
Here is a version that outputs them on the same line:
int main(int argc, char *argv[]) { int i; for (i=1;i<argc; i++) printf("%s%s",argv[i], (i < argc-1) ? " " : ""); printf("\n"); return 0; }Note the use of the conditional expression to avoid having a blank at the end of the list.
Here is another version which uses the fact that argv is a variable and not a constant.
int main(int argc, char *argv[]) { while (--argc > 0) printf("%s%s",*++argv, (argc > 1) ? " " : ""); printf("\n"); return 0; }
printf((argc > 1) ? "%s " : "%s", *++argv);
Here is an example of a program that will print out all lines from standard input which contain a given string. It returns a count of the number of lines which contain the search string.
#include <stdio.h> #include <string.h> #define MAXLINE 1000 int getline(char *line, int max); int main(int argc, char *argv[]) { char line[MAXLINE]; int found = 0; if (argc != 2) { printf("Usage %s pattern\n",argv[0]); return 0; } while (getline(line,MAXLINE) > 0) if (strstr(line, argv[1]) != NULL) { printf("%s",line); found++; } return found; }
#include <stdio.h> #include <string.h> char *getLine(); int main(int argc, char *argv[]) { char *line; int found = 0; if (argc != 2) { printf("Usage %s pattern\n",argv[0]); return 0; } while ( (line = getLine()) != NULL) { if (*line == '\0') return found; if (strstr(line, argv[1]) != NULL) { printf("%s",line); found++; } free(line); } return found; }
Suppose the program above is called find and we want the option of printing the lines not containing the string by using an optional command line argument -x (for except).
Further, suppose we want the option of including the line number that the string string was found on using -n.
All of the following should be valid:
find pattern find -x pattern find -n pattern find -x -n pattern find -n -x pattern find -nx pattern find -xn patternThere are two parts to handling this. The hard part is getting the command line parameters and setting the appropriate flags to indicate which parameters were present.
Suppose that number is true if line numbers are to be displayed and except is true if we want lines not containing the pattern. Also assume *argv points to the pattern and that lineno is a long initialized to 0.
while (getline(line, MAXLINE) > 0) { lineno++; if ((strstr(line, *argv) != NULL) != except) { if (number) printf("%lf:",lineno); printf("%s",line); found++; } }This contains some tricky code (from the book).
Here is the part of the program which sets the flags appropriately:
int main(int argc, char *argv[]) { char line[MAXLINE]; long lineno = 0; int c; int except = 0; int number = 0; int found = 0; while (--argc > 0 && (*++argv)[0] == '-') while(c = *++argv[0]) switch (c) { case 'x': except = 1; break; case 'n': number = 1; break; default: printf("find: illegal option %c\n",c); argc = 0; found = -1; break; } if (argc != 1) printf("Usage: find -x -n pattern\n"); else ... return found; }Operator Precedence Table