Thursday, June 24, 2010

Character Pointers and Functions

page 104
Since text strings are represented in C by arrays of characters, and since arrays are very often manipulated via pointers, character pointers are probably the most common pointers in C.
Deep sentence:
C does not provide any operators for processing an entire string of characters as a unit.
We've said this sort of thing before, and it's a general statement which is true of all arrays. Make sure you understand that in the lines
char *pmessage;
 pmessage = "now is the time";
 pmessage = "hello, world";
all we're doing is assigning two pointers, not copying two entire strings.
At the bottom of the page is a very important picture. We've said that pointers and arrays are different, and here's another illustration. Make sure you appreciate the significance of this picture: it's probably the most basic illustration of how arrays and pointers are implemented in C.
We also need to understand the two different ways that string literals like "now is the time" are used in C. In the definition
char amessage[] = "now is the time";
the string literal is used as the initializer for the array amessageamessage is here an array of 16 characters, which we may later overwrite with other characters if we wish. The string literal merely sets the initial contents of the array. In the definition
char *pmessage = "now is the time";
on the other hand, the string literal is used to create a little block of characters somewhere in memory which the pointer pmessage is initialized to point to. We may reassign pmessage to point somewhere else, but as long as it points to the string literal, we can't modify the characters it points to.
As an example of what we can and can't do, given the lines
char amessage[] = "now is the time";
 char *pmessage = "now is the time";
we could say
amessage[0] = 'N';
to make amessage say "Now is the time". But if we tried to do
pmessage[0] = 'N';
(which, as you may recall, is equivalent to *pmessage = 'N'), it would not necessarily work; we're not allowed to modify that string. (One reason is that the compiler might have placed the ``little block of characters'' in read-only memory. Another reason is that if we had written
char *pmessage = "now is the time";
 char *qmessage = "now is the time";
the compiler might have used the same little block of memory to initialize both pointers, and we wouldn't want a change to one to alter the other.)
Deep sentence:
The first function is strcpy(s,t), which copies the string t to the string s. It would be nice just to say s=t but this copies the pointer, not the characters.
This is a restatement of what we said above, and a reminder of why we'll need a function, strcpy, to copy whole strings.
page 105
Once again, these code fragments are being written in a rather compressed way. To make it easier to see what's going on, here are alternate versions of strcpy, which don't bury the assignment in the loop test. First we'll use array notation:
void strcpy(char s[], char t[])
 {
  int i;
  for(i = 0; t[i] != '\0'; i++)
   s[i] = t[i];
  s[i] = '\0';
 }
Note that we have to manually append the '\0' to s after the loop. Note that in doing so we depend upon i retaining its final value after the loop, but this is guaranteed in C, as we learned in Chapter 3.
Here is a similar function, using pointer notation:
void strcpy(char *s, char *t)
 {
  while(*t != '\0')
   *s++ = *t++;
  *s = '\0';
 }
Again, we have to manually append the '\0'. Yet another option might be to use a do/while loop.
All of these versions of strcpy are quite similar to the copy function we saw on page 29 in section 1.9.
page 106
The version of strcpy at the top of this page is my least favorite example in the whole book. Yes, many experienced C programmers would write strcpy this way, and yes, you'll eventually need to be able to read and decipher code like this, but my own recommendation against this kind of cryptic code is strong enough that I'd rather not show this example yet, if at all.
We need strcmp for about the same reason we need strcpy. Just as we cannot assign one string to another using =, we cannot compare two strings using ==. (If we try to use ==, all we'll compare is the two pointers. If the pointers are equal, they point to the same place, so they certainly point to the same string, but if we have two strings in two different parts of memory, pointers to them will always compare different even if the strings pointed to contain identical sequences of characters.)
Note that strcmp returns a positive number if s is greater than t, a negative number if s is less than t, and zero if s compares equal to t. ``Greater than'' and ``less than'' are interpreted based on the relative values of the characters in the machine's character set. This means that 'a' < 'b', but (in the ASCII character set, at least) it also means that 'B' < 'a'. (In other words, capital letters will sort before lower-case letters.) The positive or negative number which strcmp returns is, in this implementation at least, actually the difference between the values of the first two characters that differ.
Note that strcmp returns 0 when the strings are equal. Therefore, the condition
if(strcmp(a, b))
  do something...
doesn't do what you probably think it does. Remember that C considers zero to be ``false'' and nonzero to be ``true,'' so this code does something if the strings a and b are unequal. If you want to do something if two strings are equal, use code like
if(strcmp(a, b) == 0)
  do something...
(There's nothing fancy going on here: strcmp returns 0 when the two strings are equal, so that's what we explicitly test for.)

To continue our ongoing discussion of which pointer manipulations are safe and which are risky or must be done with care, let's consider character pointers. As we've mentioned, one thing to beware of is that a pointer derived from a string literal, as in
char *pmessage = "now is the time";
is usable but not writable (that is, the characters pointed to are not writable.) Another thing to be careful of is that any time you copy strings, using strcpy or some other method, you must be sure that the destination string is a writable array with enough space for the string you're writing. Remember, too, that the space you need is the number of characters in the string you're copying, plus one for the terminating '\0'.
For the above reasons, all three of these examples are incorrect:
char *p1 = "Hello, world!";
 char *p2;
 strcpy(p2, p1);  /* WRONG */


char *p = "Hello, world!";
 char a[13];
 strcpy(a, p);  /* WRONG */


char *p3 = "Hello, world!";
 char *p4 = "A string to overwrite";
 strcpy(p4, p3);  /* WRONG */
In the first example, p2 doesn't point anywhere. In the second example, a is a writable array, but it doesn't have room for the terminating '\0'. In the third example, p4 points to memory which we're not allowed to overwrite. A correct example would be
char *p = "Hello, world!";
 char a[14];
 strcpy(a, p);
(Another option would be to obtain some memory for the string copy, i.e. the destination for strcpy, using dynamic memory allocation, but we're not talking about that yet.)
page 106 continued (bottom)
Expressions like *p++ and *--p may seem cryptic at first sight, but they're actually analogous to array subscript expressions like a[i++] and a[--i], some of which we were using back on page 47 in section 2.8.


http://www.eskimo.com/~scs/cclass/krnotes/sx8e.html

Is a string literal in c++ created in static memory?

Where it's created is an implementation decision by the compiler writer, really. Most likely, string literals will be stored in read-only segments of memory since they never change.

In the old compiler days, you used to have static data like these literals and global but changeable data. These were stored in the TEXT (code) segment and BSS (initialized data) segment.

Even when you have code like char *x = "hello";, the hello string is stored in read-only memory while the variable x is on the stack (or writable memory at global scope). x just gets set to the address of the hello string. This allows all sorts of tricky things like string folding, so that "invalid option" (0x1000) and "valid option" (0x1002) can use the same memory block as follows:

0x1000 invalid option\0
Keep in mind I don't mean read-only memory in terms of ROM, just memory that's dedicated to storing unchangeable stuff (which may be marked really read-only by the OS).

They're also never destroyed until main() exits.

Source: http://stackoverflow.com/questions/349025/is-a-string-literal-in-c-created-in-static-memory

Tuesday, June 22, 2010

Shell Loop Interaction with SSH

A flawed method to run commands on multiple systems entails a shell while loop over hostnames, and a Secure Shell (SSH) connection to each system. However, the default standard input handling of ssh drains the remaining hosts from the while loop:
#!/bin/sh

# run hostname command on systems listed below; will only work for
# the first host
while read hostname; do
ssh $hostname hostname
done <
example.com
example.org
EOF
The hostname command will only be run on the first host connected to, as ssh will pass the remaining hostnames in the while loop to hostname as standard input. hostname ignores this input silently, and the while loop then exits, as no hosts remain to connect to.
Any command that reads from standard input will consume the rest of the items to loop over, as illustrated below using the cat command.
#!/bin/sh

while read line; do
echo "line: $line"
cat
done <
foo
bar
zot
EOF
The cat should print the remaining items of the loop to standard output, as by default it reads from standard input.
$ sh test
line: foo
bar
zot
To avoid this problem, alter where the problematic command reads standard input from. If no standard input need be passed to the command, read standard input from the special/dev/null device:
#!/bin/sh

while read hostname; do
ssh $hostname hostname < /dev/null
done <
example.com
example.org
EOF
Another option: use the -n option to ssh, which prevents ssh from reading from standard input:
ssh -n $hostname hostname
However, sometimes standard input must be passed to the remote system, for example when listing, editing, then updating crontab(5) data. The first ssh instance disables passing standard input, while the second does not, as the updated crontab(5) data is passed via standard input over ssh:
while read hostname; do
ssh -n $hostname crontab -l | \
grep -v rdate | \
ssh $hostname crontab -
done

Alternatives & Caveats

  • for loop - a common alternative, and perhaps useless use of cat, instead loops over the hostnames via for host in `cat hostlist`; …. Beware extraneous IFS related data in the file, though this should not be a concern for hostnames.
  • $ echo -n $IFS | od -bc 0000000 040 011 012 000 \t \n \0 0000004
  • while loops will not process the last line, if the file does not end with a newline. This is a risk if the hostname list origniates on a foreign system, or via any editor that does not enforce the traditional unix requirement that files end with a trailing newline.


Source: http://sial.org/howto/shell/while-ssh/

Thursday, June 17, 2010

Pointers to Pointers in C

Since we can have pointers to int, and pointers to char, and pointers to any structures we've defined, and in fact pointers to any type in C, it shouldn't come as too much of a surprise that we can have pointers to other pointers. If we're used to thinking about simple pointers, and to keeping clear in our minds the distinction between the pointer itself and what it points to, we should be able to think about pointers to pointers, too, although we'll now have to distinguish between the pointer, what it points to, and what the pointer that it points to points to. (And, of course, we might also end up with pointers to pointers to pointers, or pointers to pointers to pointers to pointers, although these rapidly become too esoteric to have any practical use.)
The declaration of a pointer-to-pointer looks like
int **ipp;
where the two asterisks indicate that two levels of pointers are involved.
Starting off with the familiar, uninspiring, kindergarten-style examples, we can demonstrate the use of ipp by declaring some pointers for it to point to and some ints for those pointers to point to:
int i = 5, j = 6; k = 7;
 int *ip1 = &i, *ip2 = &j;
Now we can set
ipp = &ip1;
and ipp points to ip1 which points to i*ipp is ip1, and **ipp is i, or 5. We can illustrate the situation, with our familiar box-and-arrow notation, like this:

If we say
*ipp = ip2;
we've changed the pointer pointed to by ipp (that is, ip1) to contain a copy of ip2, so that it (ip1) now points at j:

If we say
*ipp = &k;
we've changed the pointer pointed to by ipp (that is, ip1 again) to point to k:


What are pointers to pointers good for, in practice? One use is returning pointers from functions, via pointer arguments rather than as the formal return value. To explain this, let's first step back and consider the case of returning a simple type, such as int, from a function via a pointer argument. If we write the function
f(int *ip)
 {
  *ip = 5;
 }
and then call it like this:
int i;
 f(&i);
then f will ``return'' the value 5 by writing it to the location specified by the pointer passed by the caller; in this case, to the caller's variable i. A function might ``return'' values in this way if it had multiple things to return, since a function can only have one formal return value (that is, it can only return one value via the return statement.) The important thing to notice is that for the function to return a value of type int, it used a parameter of type pointer-to-int.
Now, suppose that a function wants to return a pointer in this way. The corresponding parameter will then have to be a pointer to a pointer. For example, here is a little function which tries to allocate memory for a string of length n, and which returns zero (``false'') if it fails and 1 (nonzero, or ``true'') if it succeeds, returning the actual pointer to the allocated memory via a pointer:
#include 

 int allocstr(int len, char **retptr)
 {
  char *p = malloc(len + 1); /* +1 for \0 */
  if(p == NULL)
   return 0;
  *retptr = p;
  return 1;
 }
The caller can then do something like
char *string = "Hello, world!";
 char *copystr;
 if(allocstr(strlen(string), &copystr))
  strcpy(copystr, string);
 else fprintf(stderr, "out of memory\n");
(This is a fairly crude example; the allocstr function is not terribly useful. It would have been just about as easy for the caller to call malloc directly. A different, and more useful, approach to writing a ``wrapper'' function aroundmalloc is exemplified by the chkmalloc function we've been using.)
One side point about pointers to pointers and memory allocation: although the void * type, as returned by malloc, is a ``generic pointer,'' suitable for assigning to or from pointers of any type, the hypothetical type void ** is not a ``generic pointer to pointer.'' Our allocstr example can only be used for allocating pointers to char. It would not be possible to use a function which returned generic pointers indirectly via a void ** pointer, because when you tried to use it, for example by declaring and calling
double *dptr;
 if(!hypotheticalwrapperfunc(100, sizeof(double), &dptr))
  fprintf(stderr, "out of memory\n");
you would not be passing a void **, but rather a double **.
Another good use for pointers to pointers is in dynamically allocated, simulated multidimensional arrays, which we'll discuss in the next chapter.
As a final example, let's look at how pointers to pointers can be used to eliminate a nuisance we've had when trying to insert and delete items in linked lists. For simplicity, we'll consider lists of integers, built using this structure:
struct list
  {
  int item;
  struct list *next;
  };
Suppose we're trying to write some code to delete a given integer from a list. The straightforward solution looks like this:
/* delete node containing i from list pointed to by lp */

 struct list *lp, *prevlp;
 for(lp = list; lp != NULL; lp = lp->next)
  {
  if(lp->item == i)
   {
   if(lp == list)
    list = lp->next;
   else prevlp->next = lp->next;
   break;
   }
  prevlp = lp;
  }
 }
This code works, but it has two blemishes. One is that it has to use an extra variable to keep track of the node one behind the one it's looking at, and the other is that it has to use an extra test to special-case the situation in which the node being deleted is at the head of the list. Both of these problems arise because the deletion of a node from the list involves modifying the previous pointer to point to the next node (that is, the node before the deleted node to point to the one following). But, depending on whether the node being deleted is the first node in the list or not, the pointer that needs modifying is either the pointer that points to the head of the list, or the next pointer in the previous node.
To illustrate this, suppose that we have the list (1, 2, 3) and we're trying to delete the element 1. After we've found the element 1, lp points to its node, which just happens to be the same node that the main list pointer points to, as illustrated in (a) below:

To remove element 1 from the list, then, we must adjust the main list pointer so that it points to 2's node, the new head of the list (as shown in (b)). If we were trying to delete node 2, on the other hand (as illustrated in (c) above), we'd have to adjust node 1's next pointer to point to 3. The prevlp pointer keeps track of the previous node we were looking at, since (at other than the first node in the list) that's the node whose next pointer will need adjusting. (Notice that if we were to delete node 3, we would copy its next pointer over to 2, but since 3's next pointer is the null pointer, copying it to node 2 would make node 2 the end of the list, as desired.)
We can write another version of the list-deletion code, which is (in some ways, at least) much cleaner, by using a pointer to a pointer to a struct list. This pointer will point at the pointer which points at the node we're looking at; it will either point at the head pointer or at the next pointer of the node we looked at last time. Since this pointer points at the pointer that points at the node we're looking at (got that?), it points at the pointer which we need to modify if the node we're looking at is the node we're deleting. Let's see how the code looks:
struct list **lpp;
 for(lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
  {
  if((*lpp)->item == i)
   {
   *lpp = (*lpp)->next;
   break;
   }
  }
 }
That single line
*lpp = (*lpp)->next;
updates the correct pointer, to splice the node it refers to out of the list, regardless of whether the pointer being updated is the head pointer or one of the next pointers. (Of course, the payoff is not absolute, because the use of a pointer to a pointer to a struct list leads to an algorithm which might not be nearly as obvious at first glance.)
To illustrate the use of the pointer-to-pointer lpp graphically, here are two more figures illustrating the situation just before deleting node 1 (on the left) or node 2 (on the right).

In both cases, lpp points at a struct node pointer which points at the node to be deleted. In both cases, the pointer pointed to by lpp (that is, the pointer *lpp) is the pointer that needs to be updated. In both cases, the new pointer (the pointer that *lpp is to be updated to) is the next pointer of the node being deleted, which is always (*lpp)->next.
One other aspect of the code deserves mention. The expression
(*lpp)->next
describes the next pointer of the struct node which is pointed to by *lpp, that is, which is pointed to by the pointer which is pointed to by lpp. The expression
lpp = &(*lpp)->next
sets lpp to point to the next field of the struct list pointed to by *lpp. In both cases, the parentheses around *lpp are needed because the precedence of * is lower than ->.
As a second, related example, here is a piece of code for inserting a new node into a list, in its proper order. This code uses a pointer-to-pointer-to-struct list for the same reason, namely, so that it doesn't have to worry about treating the beginning of the list specially.
/* insert node newlp into list */

 struct list **lpp;
 for(lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
  {
  struct list *lp = *lpp;
  if(newlp->item < lp->item)
   {
   newlp->next = lp;
   *lpp = newlp;
   break;
   }
  }
 }



Source http://www.eskimo.com/~scs/cclass/int/sx8.html

Wednesday, June 16, 2010

What is an lvalue and rvalue in C

Lvalue or location value is an address that is stored into while rvalue is the "read" value, ie., value of a constant or the value stored at a location. In the assignment

a = 31;

we have the lvalue of a used on the left hand side and the integer contant value 31 assigned to this location.

In the assignment

b = a;

we have the rvalue of a (31) used to assign to the lvalue of b . So depending on which side of an assignment, we use the variable a , we get two different behaviors.

Source: http://www.quickembeddedtips.com/what-lvalue-and-rvalue-c

Friday, June 11, 2010

Formatting a Date Using a Custom Format

http://www.exampledepot.com/egs/java.text/FormatDate.html






Formatting a Date Using a Custom Format

A pattern of special characters is used to specify the format of the date. This example demonstrates some of the characters. For a complete listing, see the javadoc documentation for the SimpleDateFormat class.
Note: This example formats dates using the default locale (which, in the author's case, is Locale.ENGLISH). If the example is run in a different locale, the text (e.g., month names) will not be the same.


Thursday, June 10, 2010

UNIX mail with Attachment

by Bruce Knox  bknox @t uaex.edu     Oracle Database Programmer/Analyst                                       Copyright 2009     last updated 05/26/10                
Creating email with a text message and an attachment from standard UNIX.  mirror at http://betwinx.com/email_with_attachment.htm
The following is for instructional purposes and provides a solution to UNIX's mail not directly providing for attachments.  While you can have attachments (by using uuencode piped to mail) or send a text message using mail, you must take some extra steps to include both in the same email. 
The example below has been tested on AIX (Korn Shell) and may be different on other flavors of UNIX.  The example sends a report file (unix_attachment.lst) as an attachment.  The text message file (message.txt) will become the body of the email.
# Create the email message text and the report file.
# Note that the final Line Feed (LF) and
 Carriage Return (CR) are critical.
# That is, the last line of text in both files must be ended.

# to check our test files:
# cat message.txt should give:

$ cat message.txt
Message Text Line1 This is the email message text
Message Text Line2
Message Text Line3

Hope this helps, Bruce
$

# the $ prompt above should be on its own line
# cat unix_attachment.lst should give:

$ cat unix_attachment.lst
Report Line1 This is the Attached Report
Report Line2
Report Line3
$

# the $ prompt above should be on its own line

# uuencode the attachment file

/usr/bin/uuencode unix_attachment.lst email_attachment.lst > attachment.txt

# note that the uuencode'd file will contain an internal file label of email_attachment.lst

# concatenate or combine the email message and the uuencode'd attachment

cat message.txt attachment.txt > combined.txt

# the combined text file looks a bit strange:

$ cat combined.txt
Message Text Line1 This is the email message text
Message Text Line2
Message Text Line3

Hope this helps, Bruce
begin 666 email_attachment.lst
M4F5P;W)T($QI;F4Q(%1H:7,@:7,@=&AE($%T=&%C:&5D(%)E<&]R=`I297!O
6
`
end
$


# note that the "begin 666 email_attachment.lst" starts at the begining of a line of text

# finally, mail the combined file

mail -s "Message with Attachment" bknox @t uaex.edu < combined.txt
(Just give it a real email address. Yes, I did get lots of test messages before I broke my example address;)

While instructive, this example leaves a wide trail of work files.  To help you remove them:
rm message.txt
rm unix_attachment.lst
# Note that rm email_attachment.lst is not a file on the sending server.
rm attachment.txt
rm combined.txt

Wednesday, June 09, 2010

The Korn shell .profile and .kshrc

The Korn shell (see ksh(1)) uses two startup files that allow users to customize their shell environment: a $HOME/.profile (if one exists) and the startup file specified by the ENV environment variable (if set and exported). Typically,$HOME/.kshrc is the file name used as the value of the ENV variable, however the startup file for ksh can be named any valid file name and is not constrained to be .kshrc.kshrc is not a startup file hardcoded into ksh, but rather a common name that is used for the ksh startup file specified (optionally) by the ENV environment variable in the users environment.
The .profile is read once, by your login ksh. The ENV file is read by each invocation of ksh, if ENV is defined in the current environment. Typically, users define ENV in their .profile file, and then this variable is available to all future child shells (unless ENV is unset).
The ENV file is often used for function and alias definitions, and setting ksh options.
A typical Korn shell .profile might look something like this:

1  :
2  # @(#) profile 23.1 91/04/03
3  #
4  # .profile -- Commands executed by a login Korn shell
5  #
6  # Copyright (c) 1990-1998 The Santa Cruz Operation, Inc.
7  # All rights reserved.
8  #
9  # This Module contains Proprietary Information of the Santa Cruz
10 # Operation, Inc., and should be treated as Confidential.
11 #
12 PATH=$PATH:$HOME/bin:.   # set command search path
13 export PATH
14 if [ -z "$LOGNAME" ]; then
15   LOGNAME=`logname`  # name of user who logged in
16   export LOGNAME
17 fi


18 MAIL=/usr/spool/mail/$LOGNAME  # mailbox location
19 export MAIL
20 if [ -z "$PWD" ]; then
21 PWD=$HOME   # assumes initial cwd is HOME
22 export PWD
23 fi
24 if [ -f $HOME/.kshrc -a -r $HOME/.kshrc ]; then
25  ENV=$HOME/.kshrc  # set ENV if there is an rc file
26  export ENV
27 fi
28 # use default system file creation mask (umask)
29 eval `tset -m ansi:ansi -m $TERM:?${TERM:-ansi} -r -s -Q`
30 # If job control is enabled, set the suspend character to ^Z (control-z):
31 case $- in
32 *m*) stty susp '^z'
33  ;;
34 esac
35 set -o ignoreeof   # don't let control-d logout
36 case $LOGNAME in   # include command number in prompt
37 root) PS1="!# " ;;
38 *) PS1="!$ " ;;
39 esac
40 export PS1


line 1
Contains a single colon that says ``this is a Bourne shell script.'' Even though this is a startup script for the Korn shell, the authors have chosen to use the more common syntax of the Bourne shell programming language. This single colon command is more portable than the (preferred) newer hash-bang syntax. It is equivalent in function to the line:
#! /bin/sh
lines 2-11
Contain comments.
line 12
Sets the path definition in exactly the same way as the preceding Bourne shell .profile: ``set the path equal to the current path, the bin in the home directory, and the current directory.''
line 13
Exports the path to any subshells. This way, you do not have to include a path definition in your .kshrc.
lines 14-17
Set up a variable called LOGNAME, which is used in the following MAIL setting (line 18). Literally, these lines say ``if checking for the value of LOGNAME returns a zero-length string (that is, if LOGNAME is not set), then set LOGNAME to the output of the logname command. Then, export the LOGNAME variable to all subshells.''
line 18
Tells the shell where to look for mail, using the variable LOGNAME.
line 19
Exports the mail location to all subshells.
lines 20-23
Check to see if a variable is already set, and if it is not, set the variable. These lines are similar to lines 14-17. In this case, PWD is being set to the home directory.
lines 24-27
Check for a .kshrc file in the home directory, and set the ksh variable ENV to this file if it exists. ksh looks in the file pointed to by the ENV variable to set up the environment for every new ksh; you need to tell it explicitly to look in ~/.kshrc for ENV definitions. Literally, these lines say ``if a file called .kshrc exists in the home directory and the file is readable, then set ENV to point to this file, and export ENV.''
line 28
Contains a comment. Just as in the preceding Bourne shell .profileumask is not set here. The authors have chosen to use the default system umask rather than resetting it on a per-user basis.
line 29
Sets up the terminal type using tset(1), as explained in the preceding Bourne shell .profile.
lines 30-34
Test to see if job control is enabled, and if it is, set the suspend character to Z. Job control is a Korn shell feature that lets you move jobs you are processing from the foreground to the background and vice versa. You use the suspend character to suspend a job temporarily that is running in the background.
line 35
Tells the shell to ignore single end-of-file (EOF) characters. This is what you set to stop D from logging you out.
lines 36-40
Set up the prompt based on the value of LOGNAME. For normal users, the prompt is the current command number followed by a ``$''; for root (the superuser), the prompt is the current command number followed by a ``#''.

A typical .kshrc might look like this:
1  :
2  #
3  # .kshrc -- Commands executed by each Korn shell at startup
4  #
5  # @(#) kshrc 1.1 90/03/13
6  #
7  # Copyright (c) 1990-1998 The Santa Cruz Operation, Inc.
8  # All rights reserved.
9  #
10 # This Module contains Proprietary Information of the Santa Cruz
11 # Operation, Inc., and should be treated as Confidential.
12 #
13 # If there is no VISUAL or EDITOR to deduce the desired edit
14 #  mode from, assume vi(C)-style command line editing.
15 if [ -z "$VISUAL" -a -z "$EDITOR" ]; then
16 set -o vi
17 fi

line 1
Tells the shell that this is a Bourne shell script by starting the script with a single colon, as you have seen before.
lines 2-14
Contain comments. These make up the bulk of this brief .kshrc.
lines 15-17
Set up vi(1) as the default editor ksh uses when you want to edit a command line. Literally, these lines say ``If the VISUAL variable is not set, and the EDITOR variable is not set, then turn on (set -o) the vi option.''


© 1999 The Santa Cruz Operation, Inc. All rights reserved.
UnixWare 7 Release 7.1.1 - 5 November 1999 



Source: http://docsrv.sco.com/SHL_custom/The_Korn_shell_profile_and_kshrc.html

Thursday, June 03, 2010

Local and Global Variables

The "scope" of a variable refers to the variable's visibility within a program. Variables which are accessible only to a restricted portion of a program are said to have "local scope." Variables that are accessible from anywhere in the program, however, are said to have "global scope."In JavaScript, variables fall into two major categories: global and local. Global variables are accessible from anywhere in the program and retain their values until the document is unloaded. Local variables, on the other hand, are created during function calls for temporary use and are accessible only within the functions that create them.

In this article I will demonstrate the use of global and local variables in JavaScript, explain the differences between them, and demonstrate why both types are useful. It is assumed that you are familiar with other aspects of JavaScript programming and that you know what a variable is.


Source: Secure Coding in C and C++ http://www.informit.com/articles/article.aspx?p=430402&seqNum=4

global variables

The following JavaScript example creates two global variables (year and month), assigns values to them, and then prints their values:




year = 1997; function make_month_variable () { month = 2; } make_month_variable (); document . write ("year=" + year + " and month=" + month);
If you are familiar with traditional structured programming languages, such as Pascal or C, you might see some strange things in this code:
  1. Variables are not formally declared before values are assigned to them.
  2. Although the variable month is created inside a function, it is not actually used until after the function returns.
Global variables can be created anywhere in JavaScript code, simply by assigning initial values to them.* Once created, global variables can be accessed from any part of the script and retain their values until the document is unloaded.In JavaScript, newly created variables are assumed to be global, regardless of where they are created, unless explicit measures are taken to make them local. In the example shown above, the variable month is created when the function is called, not defined. After the function returns, however, the month variable retains its definition. (Otherwise, the write statement would result in a JavaScript error.)
In summary, you should use global variables to store values that
  • must be maintained throughout the life of the document (i.e., until the document is unloaded) or
  • need to be accessed from many points in the program.
If your functions are using global variables that don't satisfy either of these two requirements, then you should consider rewriting them so that they use local variables instead.

local variables

Local variables store temporary variables during a short, well-defined block of code, such as a function, and are accessible only within the block where they are defined. Local variables can only be created in functions; this is done by preceding the first instance of the variable's name with the keyword var. In the example shown below, a local variable named x is created and initialized with the value 5.
function foo ()
{
 var x;
 x = 5;
 .
 .
 .
}
 ...or... 
function foo ()
{
 var x = 5;
 .
 .
 .
}
By the way, function parameter variables are considered local variables. (There are a few exceptions to this rule, but mentioning them here will only make things more complicated. :-)Local variables are accessible only in the functions where they are created. When functions exit, all of their local variables are automatically destroyed.

global and local variables with the same names

A potential ambiguity arises when two distinct variables -- one global and one local -- have the same names. The JavaScript interpreter resolves this ambiguity by giving priority to local variables whenever possible. Thus, it is possible for global variables to become masked, or hidden from the interpreter's view, when local variables exist by the same names. Although masked global variables retain their values, they are not (easily) accessible until the local variables masking them fall out of scope.Local variables fall out of scope in two ways:
  1. A function exits and its local variables are automatically destroyed.
  2. A function calls another function, thus suspending the first function and all of its local variables.
In the first case, the variables fall out of scope simply because they cease to exist. In the second case, the local variables are only temporarily out of scope and will become visible again when the called function returns.Each time a function is entered, a separate "variable space" is created for the function's local variables. Thus, even when a function repeatedly calls itself, the local variable space created for the outer function call is unrelated to the variable space created for the inner function call.

an example

The following example is given to illustrate the behavior of global and local variables. This example will also demonstrate how local variables can mask global variables. Consider the JavaScript code shown below:




function function_1 () { var x = 5; document . write ("&amp;amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;amp;gt;Inside function_1, x=" + x); function_2 (); document . write ("&amp;amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;amp;gt;Inside function_1, x=" + x); } function function_2 () { document . write ("&amp;amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;amp;gt;Inside function_2, x=" + x); } x = 1; document . write ("&amp;amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;amp;gt;Outside, x=" + x); function_1 (); document . write ("&amp;amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;amp;gt;Outside, x=" + x);
When executed, the values of two distinct variables, both named x, will be printed. The following table describes the process:
explanationillustrationprogram output
A global variable named x is created and initialized with the value 1. This value is output to the document.Outside, x=1
function_1 is called. As it executes, a local variable named x is created and set to 5. Because this local variable has the same name as the global variable, the global variable is masked and the function's first write statement outputs the value 5, not 1.Inside function_1, x=5
function_1 calls function_2. Because function_2 cannot see function_1's variables, the reference to x in function_2 is interpreted as a reference to the global variable. Thus, a value of 1 is written to the document.Inside function_2, x=1
When function_2 returns, however, function_1 continues where it left off, and the local variable comes out of hiding. Thus, a value of 5 is again written to the document.Inside function_1, x=5
Finally, when function_1 finishes, the local variable x is destroyed and the global variable is the only one left. Thus, a value of 1 is written to the document.Outside, x=1

conclusion

So what's the big deal about local and global variables? Why not make them all global and be done with it?Decades ago, when system memory was expensive, local variables were used to conserve memory. Variables were created on demand, used for a while, and then destroyed so that the memory used to store their values could be recycled for other variables. Although this once was a pretty good reason for using local variables, it is hardly worth mentioning in a JavaScript environment. There are better reasons than this.
Experienced programmers support a programming philosophy called "the principle of least privileges." This philosophy says that if the accessibility of a program resource, such as a function or variable, is restricted to just those portions of the program where such accessibility is required, then the programmer is less likely to introduce errors into the code without noticing them quickly.
Another good reason for using local variables is that less effort is required to keep track of variable names. Since each function call results in the creation of a new variable name space, different functions can use the same variable names without treading on each other's variables.
For these reasons, it is considered good programming practice to use local variables whenever possible. In JavaScript, this means your functions should use local variables to store temporary values that will not be needed after the function returns -- loop variables, for example. Adopting a habit of using local variables whenever possible will help you avoid subtle JavaScript coding errors that might not be noticed until after your web page is published.


Memory Allocation in C Programs

The C language supports two kinds of memory allocation through the variables in C programs:

  • Static allocation is what happens when you declare a static or global variable. Each static or global variable defines one block of space, of a fixed size. The space is allocated once, when your program is started (part of the exec operation), and is never freed.
  • Automatic allocation happens when you declare an automatic variable, such as a function argument or a local variable. The space for an automatic variable is allocated when the compound statement containing the declaration is entered, and is freed when that compound statement is exited. In GNU C, the size of the automatic storage can be an expression that varies. In other C implementations, it must be a constant.
A third important kind of memory allocation, dynamic allocation, is not supported by C variables but is available via GNU C library functions.
Dynamic memory allocation is a technique in which programs determine as they are running where to store some information. You need dynamic allocation when the amount of memory you need, or how long you continue to need it, depends on factors that are not known before the program runs.
For example, you may need a block to store a line read from an input file; since there is no limit to how long a line can be, you must allocate the memory dynamically and make it dynamically larger as you read more of the line.
Or, you may need a block for each record or each definition in the input data; since you can't know in advance how many there will be, you must allocate a new block for each record or definition as you read it.
When you use dynamic allocation, the allocation of a block of memory is an action that the program requests explicitly. You call a function or macro when you want to allocate space, and specify the size with an argument. If you want to free the space, you do so by calling another function or macro. You can do these things whenever you want, as often as you want.
Dynamic allocation is not supported by C variables; there is no storage class “dynamic”, and there can never be a C variable whose value is stored in dynamically allocated space. The only way to get dynamically allocated memory is via a system call (which is generally via a GNU C library function call), and the only way to refer to dynamically allocated space is through a pointer. Because it is less convenient, and because the actual process of dynamic allocation requires more computation time, programmers generally use dynamic allocation only when neither static nor automatic allocation will serve.
For example, if you want to allocate dynamically some space to hold a struct foobar, you cannot declare a variable of type struct foobar whose contents are the dynamically allocated space. But you can declare a variable of pointer type struct foobar * and assign it the address of the space. Then you can use the operators ‘*’ and ‘->’ on this pointer variable to refer to the contents of the space:
{
       struct foobar *ptr
          = (struct foobar *) malloc (sizeof (struct foobar));
       ptr->name = x;
       ptr->next = current_foobar;
       current_foobar = ptr;
     }
Source: http://www.gnu.org/s/libc/manual/html_node/Memory-Allocation-and-C.html#Memory-Allocation-and-C

Variables and Memory



When a C++ program starts, 5 distinct areas of memory are created. These are:
  • Code Space: This is where the executable instructions of the program are kept.
  • Registers: are part of the CPU that take care of internal housekeeping. Among other things, they contain an identifier that points to the next line of code that is to be executed, and the stack pointer.
  • Global Name Space: contains objects allocated by the linker which will persist for the duration of the program.
  • Stack: contains local variables, whose persistency is defined by their scope.
  • Free Store, or Heap is explicitly created and destroyed by issuing new and delete commands.
This lesson will concentrate on the differences between the last three.

The Stack

The stack is where local variables and function parameters reside. It is called a stack because it follows the last-in, first-out principle. As data is added or pushed to the stack, it grows, and when data is removed or popped it shrinks. In reality, memory addresses are not physically moved around every time data is pushed or popped from the stack, instead the stack pointer, which as the name implies points to the memory address at the top of the stack, moves up and down. Everything below this address is considered to be on the stack and usable, whereas everything above it is off the stack, and invalid. This is all accomplished automatically by the operating system, and as a result it is sometimes also called automatic memory. On the extremely rare occasions that one needs to be able to explicitly invoke this type of memory, the C++ key word auto can be used. Normally, one declares variables on the stack like this:
 
void func () { 
int i; float x[100];

...

}
Variables that are declared on the stack are only valid within the scope of their declaration. That means when the function func() listed above returns, i and x will no longer be accessible or valid.There is another limitation to variables that are placed on the stack: the operating system only allocates a certain amount of space to the stack. As each part of a program that is being executed comes into scope, the operating system allocates the appropriate amount of memory that is required to hold all the local variables on the stack. If this is greater than the amount of memory that the OS has allowed for the total size of the stack, then the program will crash. While the maximum size of the stack can sometimes be changed by compile time parameters, it is usually fairly small, and nowhere near the total amount of RAM available on a machine.

The Global Namespace

The fact that variables on the stack disappear as soon as they go out of scope limits their usefulness. Another class of variables exist that do not have this limitation. These are global and namespace variables, static class members, and static variables in functions. Global variables are accessible throughout the program, and are declared in this manner:

#include < iostream >
void func();

int i = 5;
int j = 3;
float f = 10.0;

int main() {
   int j = 7;
   
   cout << "i in main: " << i << endl;
   cout << "j in main: " << j << endl;
   cout << "global j:  " << ::j << endl;

   func();

   return 0;

}

void func() {
   float f = 20.0;

   cout << "f in func: " << f << endl;
   cout << "global f:  " << ::f << endl;
}
The output of this program will be:
i in main: 5
j in main: 7
global j:  3
f in func: 20.0
global f:  10.0
Local variables take precedence over global variables of the same name. If both are defined as shown above for the variable int j, then j refers to the local copy, whereas ::j refers to the global copy.Despite their attraction, global variables are very dangerous, and should be avoided. The permit uncontrolled access to data, which runs counter to the object nature of C++ programming.
When data is common to, or must be shared amongst all instances of a class, one can use static variables:

class Muon {
 public:
   Muon(float E):Energy(E) { MuonsInEvent++; }
   ~Muon() {MuonsInEvent--; }

   static int MuonsInEvent;

 private:
   float Energy;

};

int Muon::MuonsInEvent = 0;

int main() {

   Muon *muons[10];
   int nummuons;

   for (int i=0; i<10; i++) {
       muons[i] = new Muon(0.);
   }

   nummuons = Muon::MuonsInEvent;   

....

}

Here the integer MuonsInEvent is static, and common to all instances of the Muon class. The declaration of MuonsInEvent does not define an integer, and no storage space is set aside. So the variable must be defined and initialized, as it is on the 13th line. Since it was declared public, it can then be accessed directly in main() by its class reference, and not by a reference to a specific instance of the class. If one wishes to restrict access to the static variable, as is often wise, it can be declared private, and then only member functions of the class can access it, just like a normal private variable.Member functions of a class can also be declared static. They exist not in an object, but in the scope of a class, and can thus be called without having an object of that class:

class Muon {
 public:
   Muon(float E):Energy(E) { MuonsInEvent++; }
   ~Muon() {MuonsInEvent--; }

   static int GetNumMuons() { return MuonsInEvent; }

 private:
   float Energy;
   static int MuonsInEvent;

};

int Muon::MuonsInEvent = 0;

int main() {

   Muon *muons[10];
   int nummuons;

   for (int i=0; i<10; i++) {
       muons[i] = new Muon(0.);
   }

   nummuons = Muon::GetNumMuons();   

....

}

Note that static member functions do not have a this pointer, and therefore cannot be declared const. And since member data variables are accessed in member functions using the this pointer, static member functions cannot access any non-static member variables.Furthermore, static variables should not be used as a pseudo-global variable. While there are certain distinct implementations where they are mandated, static variables and functions should be used with caution. If you find yourself using them frequently, there is a significant chance that your design is at fault. This is especially true for Level 3 code, as tools are instantiated at the beginning of the run, and thus their members are easily accessible at any time thereafter.

The Free Store

The main problem with local variables, is that they don't persist. As soon as a function returns, all the local variables declared within it vanish. While it is possible to get around this with global variables, this is not wise. Instead, one can make use of the free store, or heap as it is often called.Variables and objects are declared on the heap using the keyword new, and are referenced using pointers. new will attempt to allocate the requested memory on the heap, and will throw a bad_allocexception if it can not. While running out of memory is not usually a problem, when dealing with large programs it is often wise to check:

int *pI;

try { pI = new int; }
catch(std::bad_alloc) {
    cout << "ERROR: no more memory\n";
    return(1);
}

.....

delete pI;
Once you're done with something declared on the heap, it must be explicitly freed using the keyword delete. If this is not done, and the pointer is reassigned, a memory leak occurs. The original memory becomes unavailable, and cannot be accessed. If this is done many times, then eventually all the available memory will be gobbled up, and your program will crash.The heap is where the vast majority of your variables should be declared. This is because the heap is far larger than the stack, and once something is placed there, it won't disappear until you tell it to, avoiding the use of those nasty global variables.
Note that most memory managers are greedy: even when memory is properly freed with delete, it is not really returned to the OS. That is, if your program allocates 1000 bytes, the size of the program in memory will grow to about that size. If you then free 1000 bytes, the program will not release the memory back to the OS - it will still look like it owns 1000 bytes of system memory. However you will have to then reallocate 1001 bytes of memory before the program size will grow again. Only when the program ends will this memory be returned to the system.
An interesting note: on the SGI, the preceding paragraph is correct. However, it seems that the memory manager in Linux is more intelligent. When space on the heap is deleted in Linux, the allocated memory is returned to the operating system. Depending on the application, this can be a good or a bad thing.
When checking for an out of memory condition, one can get a little fancier, and make use of the new function set_new_handler() which specifies what new will do when it fails. You still need to try/catchthe exception though:

void out_of_store() {
   cerr << "ERROR: operator new failed: out of store\n";
   throw std::bad_alloc();
}

int main() {

   ....

   int *pI;
   set_new_handler(out_of_store);

   try { pI = new int; }
   catch(std::bad_alloc) {
      return(1);
   }

   ....

}

If you want your code to follow the standard C syntax and return a null pointer when new fails, then the form new(nothrow) must be used:

int *pI;

pI = new(nothrow) int;
if (pI == NULL) {
   cout << "ERROR: no more memory\n";
   return(1);
}

When using the KAI compiler, if the compiler parameter --no_exceptions is used, new is implemented as new(nothrow). Currently, g++ is not smart enough to do this.

Source: http://annwm.lbl.gov/~leggett/vars.html