310 likes | 402 Views
15-213 C Primer Session – 1/25/01. Outline Hello World Command Line Arguments Bit-wise Operators Dynamic Memory / Pointers Function Parameters Structures. 1. Hello World. #include <stdio.h> int main( int argc, char *argv[]) { printf(“Hello World<br>”); return 0; }.
E N D
15-213 C Primer Session – 1/25/01 Outline • Hello World • Command Line Arguments • Bit-wise Operators • Dynamic Memory / Pointers • Function Parameters • Structures
1. Hello World #include <stdio.h> int main(int argc, char *argv[]) { printf(“Hello World\n”); return 0; }
Hello World (Ver. 2) #include <stdio.h> #define MYSTRING “Hello World\n” int main(int argc, char *argv[]) { printf(MYSTRING); return 0; }
Hello World (Ver. 3) #include <stdio.h> #ifdef HELLO #define MYSTRING “Hello World\n” #else #define MYSTRING “Goodbye World\n” #endif int main(int argc, char *argv[]) { printf(MYSTRING); return 0; }
2. Command Line Arguments • ls –l *.txt • How does a program obtain the ‘-l’ and ‘*.txt’? • Use the argc and argv parameters to main() • argc – Number of arguments (including program name) • argv – Array of strings of all arguments (including program name)
#include <stdio.h> main(int argc, char *argv[]) { int j, sum; char *pchar; printf ("Program called : %s\n", *argv ); /* print 0th arg, program called */ if ( argc < 4 ) printf ( "Not enough arguments\n" ); /* see if enough args to perform op */ else { pchar = *(argv + 1); /* get pointer to 1st arg */ if ( *pchar == '+' ) /* if +, continue */ { sum = 0; printf ( "Numbers : " ); for ( j = 2; j < argc; j++ ) { sum += atoi ( *(argv + j) ); /* each arg -> int, add to sum */ printf ( "%s ", *(argv + j) ); /* print argument */ } printf ( "\nSum : %i\n", sum ); /* print sum */ } else printf ( "Unsupported\n" ); /* operation unsupported */ } }
3. Bit-wise OperatorsExample Problems /* * bitNor - ~(x|y) using only ~ and & * Example: bitNor(0x6, 0x5) = 0xFFFFFFF8 * Legal ops: ~ & * Max ops: 8 * Rating: 1 */ int bitNor(int x, int y) { } return (~x & ~y);
/* * logicalShift - shift x to the right by n, * using a logical shift * Can assume that 1 <= n <= 31 * Examples: logicalShift(0x87654321,4) = 0x08765432 * Legal ops: ~ & ^ | + << >> * Max ops: 16 * Rating: 3 */ int logicalShift(int x, int n) { } /* Shift normally, using XOR to clear any bits * on the left of the result that should always * be 0 instead of the sign */ return (x >> n) ^ (((x & (1 << 31)) >> n) << 1);
/* * bang - Compute !x without using ! * Examples: bang(3) = 0, bang(0) = 1 * Legal ops: ~ & ^ | + << >> * Max ops: 12 * Rating: 4 */ int bang(int x) { } int minus_x = ~x+1; /* Cute trick: 0 is the only value of x * for which neither x nor -x are negative */ int bits = (minus_x | x) >> 31; /* -1 or 0 */ return bits + 1;
4. Dynamic Memory & Pointers • Java manages memory for you, C does not • C requires the programmer to allocate and unallocate memory • For instance, int x tells C to allocate 4 bytes for an integer • Unknown amounts of memory can be allocated dynamically during run-time with malloc() and unallocated using free()
Code! #include <stdio.h> #include <string.h> #define HELLO_MIXED "Hello world!" #define HELLO_CAPS "HELLO WORLD!" int main (int argc, char *argv) { char *original_string; char *copied_string; int index; /* Allocate space for the string. * Strings are terminated with a NULL. * Don't forget to include space for this terminator. */ original_string = (char *) malloc (strlen (HELLO_MIXED) + 1); if (!original_string) { printf ("malloc() has failed\n"); exit (-1); }
/* Initialize the string */ strncpy (original_string, HELLO_MIXED, strlen (HELLO_MIXED)); /* 1st attempt to copy the string */ copied_string = original_string; /* It looks like it worked */ printf ("Original String: %s\nCopied String: %s\n\n", original_string, copied_string); /* Now, let's change the original string to be all uppercase */ strncpy (original_string, HELLO_CAPS, strlen (HELLO_CAPS)); /* Let's take a look at those two strings again */ printf ("Original String: %s\nCopied String: %s\n", original_string, copied_string); /* What happened? We copied the address, not the content. * We made an alias */ printf ("Original String address: 0x%p\nCopied String Address: 0x%p\n\n", original_string, copied_string);
/* To fix this, we could allocate space * for a new string using malloc() * and then use strncpy() to copy the contents, as before. But, we * can actually do this in one step with strdup() */ copied_string = strdup(original_string); /* Now, let's test things again */ /* They look the same, but are they actually different? */ printf ("Original String: %s\nCopied String: %s\n\n", original_string, copied_string); /* Let's see */ strncpy (original_string, HELLO_MIXED, strlen (HELLO_CAPS)); /* Perfect. This time it works */ printf ("Original String: %s\nCopied String: %s\n", original_string, copied_string); printf ("Original String address: 0x%p\nCopied String Address: 0x%p\n\n", original_string, copied_string);
/* Strings are actually arrays of characters. We can access the * characters, including the NULL, one at a time by using their * address. Notice the use of the * operator to dereference a * character pointer. Also notice that the pointer moves by * one byte each time -- what one would expect from "++". */ /* Notice strlen() + 1. strlen() doesn't count the NULL, * but we want to see it */ for (index=0; index < (strlen (original_string) + 1); index++) { printf ("0x%p: %c (%d)\n", original_string + index, *(original_string + index), (int)*(original_string + index)); } printf ("\n");
/* We can also use a shortcut notation: original_string[index]. * The preprocessor will convert this to *(original_string + index) * for us */ for (index=0; index < (strlen (original_string) + 1); index++) { printf ("0x%p: %c (%d)\n", original_string + index, original_string[index], (int)original_string[index]); } /* Lastly, let's give back the space that we allocated * I like to set the pointers to NULL to indicate that * they are not allocated. */ free (original_string); original_string = NULL; free (copied_string); copied_string = NULL; return 0; }
Integer Arrays #include <stdio.h> #define ARRAY_COUNT 5 int main (int argc, char *argv) { int *int_array; int index; /* Allocate space for the ints * Only strings are null terminated -- int arrays are not. * * Here, the use of sizeof() is critical * -- ints are more than 1 byte */ int_array = (int *) malloc (ARRAY_COUNT * sizeof(int)); if (!int_array) { printf ("malloc() has failed\n"); exit (-1); }
/* Initialize the array */ for (index=0; index < ARRAY_COUNT; index++) { *(int_array + index) = index; } /* Make sure it worked * Notice the use of the & operator. This returns the address of * an object in memory. */ for (index=0; index < ARRAY_COUNT; index++) { printf ("int_array[%d]=%d at address 0x%p (decimal %d)\n", index, int_array[index], &(int_array[index]), &(int_array[index])); } printf ("\n");
/* But wait! Why did that work? We only added one, * and integers are larger than one byte. * * The joys of "Pointer Arithmetic". When adding or * incrementing pointers, C automatically adds or * increments multiples of the size of the data type. * * Take a second look at the output of the loop and the * addresses. * * Now, take a look at the size of int printed below */ printf ("sizeof(int) = %d bytes", sizeof(int)); printf ("\n"); /* Clean-up */ free (int_array); int_array = NULL; return 1; }
5. Function Parameters • Function arguments are passed “by value”. • What is “pass by value”? • The called function is given a copy of the arguments. • What does this imply? • The called function can’t alter a variable in the caller function, but its private copy.
Example 1 Example 1: void swap_1(int a, int b) { int temp; temp = a; a = b; b = temp; } Q: Let x=3, y=4, after swap_1(x,y); x =? y=? A1: x=4; y=3; A2: x=3; y=4;
Example 2: swap_2 Example 2: void swap_2(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } Q: Let x=3, y=4, after swap_2(&x,&y); x =? y=? A1: x=3; y=4; A2: x=4; y=3;
Example 3: scanf Example 3: #include <stdio.h> int main() { int x; scanf(“%d\n”, &x); printf(“%d\n”, x); } Q: Why using pointers in scanf? A: We need to assign the value to x.
Using Libraries • What are libraries? • Using libraries • Finding library functions > man printf #include <stdio.h> ... printf(“Hello, world!\n”); ...
I/O operations • Header: stdio.h • Functions: void printf(char * format, ...); int scanf(char * format, ...); ...
String operations • Header: string.h • Functions: int strlen(char * str); int strcmp(char * str1, char * str2); char * strcpy(char * dest, char * orig); char * strchr(char * str, char ch); ...
6. Structures • Structures enables a programmer to group together related data • Sort of like a class, but structures only encapsulate data
More Code! #include <stdio.h> #include <string.h> #include <malloc.h> #define MAX_STRING 20 #define MAX_STUDENTS 6 /* A C struct is a data type that groups of objects of * possibly different types into a single object. */ struct student { char first[MAX_STRING]; char last[MAX_STRING]; char id[MAX_STRING]; int age; }; int main(int argc, char **argv) { int n, index;
/* Allocate memory for an array of students. * Make sure to use sizeof when allocating memory for a struct. * Because of memory alignment issues, * struct may require more memory * than you think, so shouldn't hand calculate size. */ struct student *roster = (struct student *) malloc(MAX_STUDENTS * sizeof(struct student)); struct student tmpStudent; /* Open text file with all of the student information * for reading. */ FILE *fid = fopen("students.txt", "r"); if(!fid) { printf("Error opening file for reading.\n"); return 1; }
/* FILL IN STRUCT ARRAY */ index = 0; while(fid && (index < MAX_STUDENTS)) { /* fscanf reads from the supplied stream 'fid‘ * under a controlled format * and assigns the converted values to the args provided. * Note: Each argument must be a pointer. * fscanf returns 0 when the format is exhausted * returns EOF if end of file or an error occurs * else returns number of items converted. */ n = fscanf(fid, "%s %s %s %d\n", tmpStudent.first, tmpStudent.last, tmpStudent.id, &(tmpStudent.age)); if (n == 0) { printf("Error scanning file.\n"); return 1; } if (n == EOF) break;
strncpy((*(roster + index)).first, tmpStudent.first, strlen(tmpStudent.first)); strncpy((*(roster + index)).last, tmpStudent.last, strlen(tmpStudent.last)); strncpy((*(roster + index)).id, tmpStudent.id, strlen(tmpStudent.id)); (*(roster + index)).age = tmpStudent.age; /* Much easier way to do this copying */ memcpy((void *) (roster + index), (const void *) &tmpStudent, sizeof(struct student)); index++; }
/* PRINT OUT STRUCT ARRAY */ for(index = 0; index < MAX_STUDENTS; index++) { /* Notice here simpler way of accessing fields in struct. * '->' is a pre-processor shortcut for (*sptr).field */ printf("Student #%d: %s\t%s\t%s\t%d\n", index + 1, roster->last, roster->first, roster->id, roster->age); roster++; }; /* Clean-up */ free(roster); roster = NULL; fclose(fid); return 0; }