gcc stack.c rpn.c
printf("Enter format string: "); char format[200]; /* be safe? */ scanf("%s", format); /* scan reads from stdin */ printf(format, name, age);
makefile
#include <string.h> char first[40], last[40]; ... cout << "Length of " << first << ": " << strlen(first); // first becomes last: strcpy(first, last); // check if they are ordered if ( strcmp(first, last) < 0 ) cout << first << " before " << last << endl;
int strlen(const char str[]) // const: won't change array contents { int len = 0; while ( str[len] != '\0' ) ++len; return len; }
strcpy(animal, "giraffe"); char name[] = "Elizabeth"; strcpy(name, name + 2); // ALSO unsafe - never overlap the strings on these
name[0] = NULL; // or, name[0] = '\0';Any characters after the NULL don't matter. After this,
strlen(name)
returns 0.
const int LEN = 10; char word[LEN]; printf("Enter word: "); scanf("%s", word); // trusting user! word[LEN - 1] = '\0'; // but not completely... if ( word[0] != '\0' ) // at least one char { char last = word[strlen(word) - 1]; if ( last != 's' && last != 'S' ) { word[LEN - 2] = '\0'; // ensure space... strcat(word, "s"); // no need to use strncat } }
struct X {int a;};
, X
something;
is illegal in C but legal in C++
struct
: they use the C++17
standard, so their examples compile as C++ code but not as C code
typedef struct { char name[100]; int id; int term_hours, cum_hours; float term_gp, cum_gp; } Student; Student grace; strcpy(grace.name, "Grace Hopper"); grace.id = 101; grace.term_hours = 14; grace.cum_hours = 110; grace.term_gp = 49.2; grace.cum_gp = 385.0;This gives the memory map
grace | ||||||||
|
|
Student *new = malloc(sizeof(Student)); new->term_gp = new->cum_gp = 0.0; strcpy(new->name, "Help?");
sizeof(Student)
- the compiler may organize
data differently than what you expect, and this is the only robust way to
determine its size
#define NAMELEN 100 typedef struct { char name[NAMELEN]; int id; int term_hours, cum_hours; float term_gp, cum_gp; } Student;
#define
for named constants later
void print_gpa(Student stu) { printf("%.4g", (double)stu.cum_gp / (double)stu.cum_hours); }
print_gpa(grace); print_gpa(*new);
void print_gpa(const Student *stu) { double gpa = (double)stu->cum_gp / (double)stu->cum_hours; printf("%.4g", gpa); }
print_gpa(&grace); print_gpa(new);
typedef struct { int x, y; } Point; typedef struct { Point a, b; } Line;
Line image[MAXLINES];
printf("%d", image[9].a.x);
void DrawImage(const Line image[], int numLines) { for(int i = 0; i < numLines; i++) { MoveTo(image[i].a.x, image[i].a.y); LineTo(image[i].b.x, image[i].b.y); } }
gcc array.c
double underlying_data[7]; double *numbers = &underlying_data[3]; ... numbers[-1] = ... ... numbers[3] = ... // (legal values from -3 to +3)
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | ||||||
1 | ||||||
2 | ||||||
… | ||||||
9 |
#define X Yall occurrances of X (case-sensitive) are replaced by Y
#define MAX_LEN 50so
int nums[MAX_LEN];translates to
int nums[50];
#define MAX_LEN 50; int nums[MAX_LEN];translates to
int nums[50;];which won't compile
#define MAX_STRING_LENGTH 100 #define MAX_DECLARED_STRING MAX_STRING_LENGTH + 1 char name[MAX_DECLARED_STRING]; /* but see discussion below */
#define max(a, b) a > b ? a : b #define sqr(x) x * x
#define name value #define name(arguments) value
double y = max(u, v); i = sqr(j);translates to
double y = u > v ? u : v; i = j * j;
i / j * j;which is equivalent to (i / j) * j; should write:
#define sqr(x) (x * x)
#define sqr(x) ((x) * (x))
x at end: 7; y: 49
x at end: 7; y: 42
x++ + ++x
would slow down lots of
reasonable code
#define assert(test) ((test) ? cerr \ : (cerr << "Assertion failure on line " \ << __LINE__ << " of " << __FILE__ \ << ": " << #test << endl))
assert(x > 0);gives
((x > 0) ? cerr : (cerr << "Assertion failure on line " << 25 << " of " << "prog3.cpp" << ": " << "x > 0" << endl));
#ifdef _Windows cout << "This is compiled for Microsoft Windows." << endl; #else cout << "This is compiled for a non-Microsoft Windows system." << endl; #endif
#if 0 ... errant code ... #endif
// comment out following for release builds #define DEBUG ... #ifdef DEBUG ... #endif
// // util.h: utilities // #ifndef _util_h #define _util_h declarations, etc. #endif
union Message { char text[1000]; float xs[200]; } msg; strcpy(msg.text, "Hello, World"); msg.xs[0] = 3243.5234e12; msg.xs[1] = -1e5; printf("%s", msg.text);
struct Message { enum { TEXT, DATA } message_type; union MessageContents { char text[1000]; float xs[200]; } contents; } msg; ... if ( msg.message_type == TEXT ) display(msg.contents.text); else print_table(msg.contents.xs);
std::string
optimization: can store short strings in
the pointer to the buffer; pseudocode for this, assuming the least
significant byte of a pointer overlaps to the last byte in an array
of characters:
union StringContent { char *bufp; char contents[sizeof(char*)]; }; class string { private: StringContent text; int len; public: // (bitwise operations would require casts in the following) string(const char *src) : len(strlen(src) { if ( len ≥ sizeof(char*) ) { text.bufp = new char[len + 1]; strcpy(text.bufp, src); text.bufp |= 0x01; // set low order bit as flag } else { text.bufp = 0; // fast way to clear all bits strcpy(text.contents, src); // note low order bit is 0 in this case (no matter src len) } } char* c_str() { if ( text.bufp & 0x01 ) return text.bufp & ~(0x01); // clears low order bit else return &text.contents[0]; } ... };
typedef long my_type; long a = 5; my_type b = a; // ok!
typedef double meters; typedef double kilograms; meters m; ... kilograms k = m; // legal
struct Stack { int data[100]; int count; }; struct Set { int data[100]; int count; }; ... struct Stack a, b; ... a = b; // ok! ... struct Set x; x = a; // illegal!
typdef struct { int data[100]; int count; } Stack100;creates an anonymous struct that's distinct from Set, Stack.