If you have done C, but not C++ then this is ok too.
If you haven't done C or C++, then you need to learn this before you go any further.
C and C++ have different standard libraries. The most notable is the I/O libraries. All I/O calls have to be re-written from C++ to C.
However, C functions can be used in C++ programs. So you can use the C Systems API functions in C++ without any problems This approach will be used from now on: C++ programs using C system calls. That means you can continue to write programs in C++, just adding in the extra C calls as needed.
The different nature of C to C++ means that some things are done differently in C to C++. These are:
Some other things that are common to C and C++ have not been used much in ST1 and ST2 (for good reason!). These are
void
functions). Systems calls usually use this value
to signal errors
unsigned int sleep(unsigned int seconds)
int uname(struct utsname *name)attempts to read system values. If it succeeds, it returns a non-negative value. If it fails, it returns -1
NULL
pointer to signal an error. For example, the Unix function
char *getlogin()attempts to find the login name of the user. If it succeeds, it returns a pointer to the string. If it fails it returns
NULL
.
int creat(char *path, mode_t mode)attempts to create a file. If it succeeds, it returns a non-negative file descriptor. If it fails, it returns -1.
Many system calls take a structure as parameter, or return a structure as value. If the structure will be modified by the call then its address needs to be passed; if it isn't modified, then its address is passed anyway since this is more efficient.
int uname(struct utsname *name)attempts to read system values using the structure
#define _SYS_NMLN 257 struct utsname { char sysname[_SYS_NMLN]; char nodename[_SYS_NMLN]; char release[_SYS_NMLN]; char version[_SYS_NMLN]; char machine[_SYS_NMLN-65]; };
struct dirent *readdir(DIR *dp)where
struct dirent { long d_ino; __kernel_off_t d_off; unsigned short d_reclen; char d_name[256]; };This structure must be treated as read-only!
ch = tolower(ch);There are no C++ reference parameters. To change the value of a parameter you have to do your own ``call by reference'' and pass the address of the variable as the parameter. Example: The sum of two ints as a procedure rather than a function:
void sumof(int x, int y, int *z) { *z = x + y; }and use it by
int n; sumof(1, 2, &n);
#include <iostream.h> void sumof(int x, int y, int *z) { *z = x + y; } int main(int argc, char *argv[]) { int n; sumof(1, 2, &n); cout << "1+2 = " << n << '\n'; exit(0); }
The size of characters varies according to the character set used. Ascii uses 7-bit characters (always taking up 8-bits, though). ISO 8859 uses the full 8-bits. Unicode uses 16-bits. ISO 10646 uses upto 32-bits.
The sizeof()
function will return the size of an object
in bytes. This can be used to test the size of data types.
Only low-level stuff should need to do this.
#include <iostream.h> int main(int argc, char *argv[]) { cout << "char size (bytes): " << sizeof(char) << endl; cout << "short int size: " << sizeof(short int) << endl; cout << "int size: " << sizeof(int) << endl; cout << "long int size: " << sizeof(long int) << endl; cout << "int pointer size: " << sizeof(int *) << endl; exit(0); }
a == &a[0] *a == a[0]In general.
a + n == &a[n] *(a + n) == a[n]
A ``spread'' function to find the distance between largest and smallest elements of an array is
int spread(int b[], int size) { int lo, hi, i; if (size == 0) return 0; lo = hi = b[0]; for (i = 0; i < size; i++) { if (b[i] > hi) hi = b[i]; if (b[i] < lo) lo = b[i]; } return (hi - lo); }The ``spread'' function could have been written
int spread(int b[], int size) { int lo, hi, i; if (size == 0) return 0; lo = hi = b[0]; for (i = 0; i < size; i++) { if (*(b+i) > hi) hi = *(b+i); if (*(b+i) < lo) lo = *(b+i); } return (hi - lo);When an array is passed as a parameter to a function, its address is passed. This is a pointer value. The function, instead of declaring the parameter as an array could instead have declared it as a pointer.
This is a very common practice. Many library functions declare their arguments as pointers, but you have to pass in an array.
Once a parameter is a pointer, you can do pointer manipulations instead of costly array indexing. Here is another ``spread'':
int spread(int *b, int size) { int hi, lo, i; if (size == 0) return 0; lo = hi = *b; for (i = 0; i < size; i++) { if (*b > hi) hi = *b; if (*b < lo) lo = *b; b++; } return (hi - lo); }
#include <iostream.h>; #define MAX 100 int spread(int *b, int size); int main(int argc, char *argv[]) { int n; int count = 0; int a[MAX]; while (count < MAX && cin >> n) { a[count++] = n; } cout << "spread was " << spread(a, count) << endl; exit(0); } int spread(int *b, int size) { int hi, lo, i; if (size == 0) return 0; lo = hi = *b; for (i = 0; i < size; i++) { if (*b > hi) hi = *b; if (*b < lo) lo = *b; b++; } return (hi - lo); }
int a[] = {1, 2, 3}; void printit(int *a) { int n; for (n = 0; n < 3; n++) { printf("%d\n", *a); a++; } } int main(int arc, char *argv[]) { printit(a); }versus
int a[] = {1, 2, 3}; int main(int argc, char *argv[]) { for (n = 0; n < 3; n++) { printf("%d\n", *a); a++; } }The second is wrong, the first is good C style.
char str[] = "hello"; char str[] = {'h', 'e', 'l', 'l', 'o', '\0'};You can always count on the null char being at the end of a string (except sometimes). If you create a string you should ensure that you null-terminate it. Otherwise, everything breaks. Because strings end in null, a string walk looks like
while (*str != '\0') str++;Here is strlen
int strlen(char *str) { int length = 0; while (*str != '\0') { str++; length++; } return length; }Now this is where you get to see some of the special lurks that C has. You can combine the increment into the loop:
int strlen(char *str) { int length = 0; while (*str++ != '\0') length++; return length; }Indeed, since 0 = '\0' = False,
int strlen(char *str) { int length = 0; while (*str++) length++; return length; }Here is the compact form of strcpy
void strcpy(char *from, char *to) { while (*to++ = *from++) ; /* empty body */ }You do eventually get used to this. However, you could always use the more readable versions!