| Goals for this chapter: |
|
The C language offers different types of data: int for integers, double and float for real numbers and char for characters.
For example, the following declaration
int i,j;
char str[24];
float degc, degf;
are valid C data declaration.
For integers C offers differents containers of data
long pencil;
short pen;
The difference between these types
The previous definitions are variable. To set constants there are two modes:
#define PI 3.141515
#define A 90.0
#define __isascii(c) (((c) & ~0x7f) ==
0)
#define __tobody(c, f, a, args) \
(__extension__
\
({ int __res;
\
if (sizeof (c) > 1)
\
{
\
if (__builtin_constant_p
(c))
\
{
\
int __c = (c);
\
__res = __c < -128 || __c > 255 ? __c : a[__c];
\
}
\
else
\
__res = f args;
\
}
\
else
\
__res = a[(int) (c)];
\
__res; }))
const char mychar = "C Programming";
While define are const are equivalent for non-strings definitions,
only the using const is possible to define constants.
We note in the previous example that define may works like functions. We also note the Operator "? :"
This operator is equivalent to a if-then-else statement.
Suppose that you write
(A> B) ? C : D
This is equivalent to the following code:
if (A > B) {
C
} else {
D
}
For example is usefull also in return.
For example return (a>0) ? a ? b;
Now, we will resume all this data in a simgle program, printing regular data, maximum and minimum values for each variable. The limits of the C are listed in the include file, <limits.h> .
In C is also possible to use the enum, for example
enum colors {Green, Red, Yellow }
enum days { MON = 1, TUE, WED, THU, FRI, SAT, SUN }
Of course, TUE will be 2, WED will be 3, etc.
Other more complex enum definitions are:
enum { XmSTRING_DIRECTION_L_TO_R,
XmSTRING_DIRECTION_R_TO_L,
XmSTRING_DIRECTION_UNSET
= 3,
XmSTRING_DIRECTION_DEFAULT
= XmDEFAULT_DIRECTION
};
Of course, is possible to built its own types using structures and unions, See the section: Structures in this chapter.
Some examples are:
typedef enum{ XmFONT_IS_FONT, XmFONT_IS_FONTSET
} XmFontType;
typedef unsigned char XmStringDirection;
typedef union __XmStringRec *XmString;
/* opaque to outside */
typedef XmString * XmStringTable;
/* opaque to outside */
typedef char *
XmStringCharSet; /* Null term
string */
typedef char *
XmStringTag;
/* Null term string */
typedef unsigned char XmStringComponentType;
/* component tags */
C offers the possibility to print data in formated mode.
| Printf Argument | Description |
| %d %i | Print a decimal number |
| %6d | Print a decimal number with up to 6 digits |
| %f | Print a float |
| %.4f | Print a float with 4 decimals |
| %6.4f | Prints a float 6 digit float and 4 decimals |
| %u | Prints int without sign |
| %o | Prints octal numbers |
| %x, %X | Prints hexadecimal |
| %c | Prints a character |
| %s | Prints a string |
| %20s | Prints a string 20 characters long |
| %-20s | Prints a string 20 characters long alignment to left. |
In C are also used the following C escape sequence:
ASCII Name
Description
C Escape Sequence
nul
null byte
\0
bel
bell character
\a
bs
backspace
\b
ht
horizontal tab
\t
np
formfeed
\f
nl
newline
\n
cr
carriage return
\r
In the section C Operators we will offer a complete introduction to these operators, however now we will introduce the cycle for, to print sin and cos, from 0 until 64 degree.
My first serious project when I enter in UCV (Caracas - Venezuela), in 1980, was to use the faculty computer a Burroghs system which covers a big surface (about 4 normal rooms), to print a similar table.
Starting from this table and using the sin (64) and the formulae for six(x/2), I offers a proof that is possible to built the same table with a simple desk calculator, with four five operations: '+', '-', 'x', '/' and 'sqrt'. In Chapter 1, I introduce an algorithm to get the cubic root from the squared root.
#include <math.h>
main ()
{
int i;
for (i=0; i <=
64; i++) {
printf ("%d %.4f %.4f\n", i, sin(i), cos(i));
}
}
Because we use a function sin(x) that belong to the mathematical library we need to add it to the compilation line.
[root@ftosx1 Chap2]# cc sin64.c -o sin64 -lm
Then, we will have the table
[root@ftosx1 Chap2]# ./sin64
0 0.0000 1.0000
1 0.8415 0.5403
2 0.9093 -0.4161
3 0.1411 -0.9900
4 -0.7568 -0.6536
...
In C is also possible to align strings to right or left.
[root@ftosx1 Chap2]# more align.c
main()
{
char ruler [] = "012345678901234567890123456789";
char str1 [] = "Brian
Kernimgham";
char str2 [] = "C
is cool language";
printf ("%s\n", ruler);
printf ("%20s\n",
str1);
printf ("%-20s\n",
str2);
}
[root@ftosx1 Chap2]#
There are also other importants data objects like array of characters and pointers.
char * string;
char string[];
The first declaration is a pointer to char, while the second is a vector of char.
We can define for example:
char mystr[] = "Hello!"
We don't need to alloc memory for this because this happens automatically.
A simple C source explains this:
[root@ftosx1 Chap2]# more array.c
main()
{
char mystr[] = "Hello!";
puts (mystr);
printf ("%c %c\n",
mystr[0], mystr[3]);
}
[root@ftosx1 Chap2]# make array
[root@ftosx1 Chap2]# ./array
Hello!
H l
[root@ftosx1 Chap2]#
The Pointer is a variable that contains the address of another variable. Now, we will write two simple examples that generate correct situation that can create bad situations and also clear bad situations.
We can use also the pointer concept like we did in the previous example.
[root@ftosx1 Chap2]# more array2.c
main()
{
char * mystr = "Hello!";
puts (mystr);
printf ("%c %c\n", mystr[0], mystr[3]);
}
[root@ftosx1 Chap2]#
If we don't change the pointer, everything works!
[root@ftosx1 Chap2]# make array2
cc array2.c -o array2
[root@ftosx1 Chap2]# ./array2
Hello!
H l
[root@ftosx1 Chap2]#
But, if we change the pointer "everything" (for an indefinite situation) may happens.
[root@ftosx1 Chap2]# more array3.c
main()
{
char * mystr = "Hello!";
puts (mystr);
printf ("%c %c\n", mystr[0], mystr[3]);
strcpy (mystr, "We change now!");
printf ("%c %c\n", mystr[0], mystr[3]);
}
[root@ftosx1 Chap2]# make array3
cc array3.c -o array3
[root@ftosx1 Chap2]# ./array3
Hello!
H l
Segmentation fault
[root@ftosx1 Chap2]#
The previous segmentation fault happens because we try to use an unallocated memory position.
Now, we will illustrate better this problems generating a segmentation fault!
[root@ftosx1 Chap2]# more array4.c
main()
{
// Allocated variable;
char mystr[14];
strcpy (mystr, "We
change now!");
puts (mystr);
printf ("%c %c\n",
mystr[0], mystr[3]);
strcpy (mystr, "We
change now with a very very long string!");
puts (mystr);
}
[root@ftosx1 Chap2]#
[root@ftosx1 Chap2]# make array4
cc array4.c -o array4
[root@ftosx1 Chap2]# ./array4
We change now!
W c
We change now with a very very long string!
Segmentation fault
[root@ftosx1 Chap2]#
Therefore is clear that when we use pointers, pointers must point to allocated variable with the sufficient ammount of memory.
Now, we will cover an example using point to integers, and using pointers to print the information where the pointer points.
[root@ftosx1 Chap2]# more array5.c
main()
{
// Allocated variable;
int a[10];
a[0] = 0;
a[1] = 1;
a[2] = 2;
a[3] = 3;
a[4] = 4;
a[5] = 5;
a[6] = 6;
a[7] = 7;
a[8] = 8;
a[9] = 9;
printf ("%d, %d, %d\n",
a[0], a[1], a[9]);
}
[root@ftosx1 Chap2]#
Therefore, a is a simple vector where each position includes an integer that represent its position.
Now, we use a point and print the information that this pointer points!
[root@ftosx1 Chap2]# more array6.c
main()
{
// Allocated variable;
int a[10];
int *pa;
a[0] = 0;
a[1] = 1;
a[2] = 2;
a[3] = 3;
a[4] = 4;
a[5] = 5;
a[6] = 6;
a[7] = 7;
a[8] = 8;
a[9] = 9;
// Now 'pa' points
to the element 0 of the array a.
pa = &a[0];
// ... and we print
its contents
printf ("%d\n", *pa);
// Now 'pa' points
to the element 0 of the array a.
pa = &a[4];
// ... and we print
its contents
printf ("%d\n", *pa);
}
[root@ftosx1 Chap2]# make array6
cc array6.c -o array6
[root@ftosx1 Chap2]# ./array6
0
4
[root@ftosx1 Chap2]#
The line
pa = &a[0];
is equivalent to:
pa = a;
because a is equivalent to &a[0].
We can also prints the next position where points the pointer and also the n-position, where n must be a valid position.
We clean the previous example and transform it a more classical code.
[root@ftosx1 Chap2]# more array7.c
main()
{
// Allocated variable;
int a[10], i;
int *pa;
for (i=0; i<=9;
i++)
a[i] = i;
// Now 'pa' points
to the element 0 of the array a.
pa = a;
// ... and we print
its contents
printf ("%d\n", *pa+6);
}
[root@ftosx1 Chap2]#
[root@ftosx1 Chap2]# make array7
cc array7.c -o array7
[root@ftosx1 Chap2]# ./array7
6
The next step on Pointers is a vector of pointers:
We can also create a vector of Pointers, for example the declaration:
static char * myweek [] = { "Linux", "StarOffice", "KDE", "Java", "PHP", "Netscape", "Number Theory", "Relativity" };
create an array of six pointers.
These pointers automically allocated from the previous declaration.
[root@ftosx1 Chap2]# more vector_pointer.c
main(int argc, char ** argv[])
{
int i;
static char * myweek
[] = {"Linux", "StarOffice", "KDE", "Java", "PHP", "Number Theory", "Relativity"
};
for (i = 0; i <=
6; i++) {
printf ("%s\n", myweek[i]);
}
return 0;
}
[root@ftosx1 Chap2]#
[root@ftosx1 Chap2]# make vector_pointer
cc vector_pointer.c -o vector_pointer
[root@ftosx1 Chap2]# ./vector_pointer
Linux
StarOffice
KDE
Java
PHP
Number Theory
Relativity
[root@ftosx1 Chap2]#
Pointers may be passed as functions parameters, pointers may be entire structures and are used anywhere. This argument is covered in C Functions
In C programing for X11, or Motif (See X Windows Course), or Networking programming covered in this course we can find real structures declaration as follows:
struct arphdr
{
unsigned short int ar_hrd;
/* Format of hardware address. */
unsigned short int ar_pro;
/* Format of protocol address. */
unsigned char ar_hln;
/* Length of hardware address. */
unsigned char ar_pln;
/* Length of protocol address. */
unsigned short int ar_op;
/* ARP opcode (command). */
#if 0
/* Ethernet looks like this : This bit is
variable sized
however... */
unsigned char __ar_sha[ETH_ALEN];
/* Sender hardware address. */
unsigned char __ar_sip[4];
/* Sender IP address. */
unsigned char __ar_tha[ETH_ALEN];
/* Target hardware address. */
unsigned char __ar_tip[4];
/* Target IP address. */
#endif
};
In X11.h we can find:
typedef union _XEvent {
int type;
/* must not be changed; first element */
XAnyEvent xany;
XKeyEvent xkey;
XButtonEvent xbutton;
XMotionEvent xmotion;
XCrossingEvent xcrossing;
XFocusChangeEvent
xfocus;
XExposeEvent xexpose;
XGraphicsExposeEvent
xgraphicsexpose;
XNoExposeEvent xnoexpose;
XVisibilityEvent
xvisibility;
XCreateWindowEvent
xcreatewindow;
XDestroyWindowEvent
xdestroywindow;
XUnmapEvent xunmap;
XMapEvent xmap;
XMapRequestEvent
xmaprequest;
XReparentEvent xreparent;
XConfigureEvent xconfigure;
XGravityEvent xgravity;
XResizeRequestEvent
xresizerequest;
XConfigureRequestEvent
xconfigurerequest;
XCirculateEvent xcirculate;
XCirculateRequestEvent
xcirculaterequest;
XPropertyEvent xproperty;
XSelectionClearEvent
xselectionclear;
XSelectionRequestEvent
xselectionrequest;
XSelectionEvent xselection;
XColormapEvent xcolormap;
XClientMessageEvent
xclient;
XMappingEvent xmapping;
XErrorEvent xerror;
XKeymapEvent xkeymap;
long pad[24];
} XEvent;
In Xm.h we can find:
typedef struct
{
int reason;
XEvent *event;
} XmAnyCallbackStruct;
Note how structures may includes others that may be installed or not. Generally very few systems install Motif today (RedHat continues to use LessTif a Motif clone). FTOSX install OpenMotif, the original.
Now, we present an example about how we can setup our own typedefs.
Suppose that you want write a program to list your friends at college:
C offers structures and union for this kind of data, however C offers also the typedef to create our own types.
[root@ftosx1 Chap2]# more structures.c
typedef struct _student {
char name[20];
char address [50];
int id;
int age;
char sex;
} student;
main ()
{
student john;
strcpy(john.name,
"John Smith");
strcpy(john.address,
"1620 26th Street - Santa Monica");
john.id = 42571;
john.age = 18;
john.sex = 'M';
printf ("The data request is the following:\n\t%s\n\t%s\n\t%d\n\t%d\n\t%c\n", john.name, john.address, john.id, john.age, john.sex);
}
[root@ftosx1 Chap2]#
[root@ftosx1 Chap2]# make structures
cc structures.c -o structures
[root@ftosx1 Chap2]# ./structures
The data request is the following:
John Smith
1620 26th Street
- Santa Monica
42571
18
M
[root@ftosx1 Chap2]#
A union is similar to a structure but only one of its member is in use.
For example, we can define:
union {
/* prime number */
short is_prime;
/* composite */
short is_not_prime;
} is_prime
or for example:
union {
char single_name[40];
char marital_lastname[40];
char complete_divorcedname[60];
} marital_info;
Yo access members we use the classic mode: marital_info.single_name
Any data type is a set of bits. Therefore a number may be a string and a string may be a number.
These conversions are possible. For example we can covert a string (like
"3098" to its relative integer 3098, a number).
main ()
{
char string [] =
"3098";
int myint;
printf ("%d\n", myint = atoi(string));
printf ("like a test
%d\n", myint + 1);
}
[root@ftosx1 Chap2]# make atoi
cc atoi.c -o atoi
[root@ftosx1 Chap2]# ./atoi
3098
like a test 3099
The same is valid for double or float
[root@ftosx1 Chap2]# more strtod.c
#include <stdlib.h>
main ()
{
char string [] =
"-3.141516098";
double mydouble;
printf ("%f\n", mydouble = strtod(string, NULL));
printf ("like a test
%f\n", mydouble + 1);
}ec
[root@ftosx1 Chap2]#
[root@ftosx1 Chap2]# make strtod
cc strtod.c -o strtod
[root@ftosx1 Chap2]# ./strtod
-3.141516
like a test -2.141516
[root@ftosx1 Chap2]#
Is possible make also reverse operations, for example a number that become a string, but this is inmmediate.
[root@ftosx1 Chap2]# more number2string.c
#include <stdio.h>
main()
{
double mydouble =
3.141516;
char mystr[14];
sprintf (mystr, "%f\n", mydouble);
printf ("%s and its fifth character is: %c\n", mystr, mystr[4]);
}
[root@ftosx1 Chap2]#
[root@ftosx1 Chap2]# make number2string
cc number2string.c -o number2string
[root@ftosx1 Chap2]# ./number2string
3.141516
and its fifth character is: 1
[root@ftosx1 Chap2]#
Of course an analog conversion may be made from any type to any string.
Generally the reciprocal fprintf functions are the scanf function, used to join in a single string, different types.
This is normally the mode things works.