Sunday, December 20, 2009

python: redirecting the output of "print" to both stdout and to a file

#!/usr/bin/env python

import sys

class MyWriter:

    def __init__(self, stdout, filename):
        self.stdout = stdout
        self.logfile = file(filename, 'a')

    def write(self, text):
        self.stdout.write(text)
        self.logfile.write(text)

    def close(self):
        self.stdout.close()
        self.logfile.close()

# create a writer object and test it out
writer = MyWriter(sys.stdout, 'log.txt')
sys.stdout = writer

print 'test' 
Works like a charm!

source

Friday, November 27, 2009

vim: create a custom ex command to quit on ":Q"

I put this in my ~/.vimrc so that it is available in every vim session:
:command -nargs=0 Quit :qa!

Finally! I wanted this little vim tweak since quite a while. I don't want the nagging "E492: Not an editor command: Q" error message every time I type ":Q" instead of ":q".

This command simply tells vim to do a ":qa!" when the user enters ":Quit" or an abbreviation of ":Quit" such as ":Q".

Thursday, November 26, 2009

linux basics: the mysterious three load average numbers

The traffic analogy

A single-core CPU is like a single lane of traffic. Imagine you are a bridge operator ... sometimes your bridge is so busy there are cars lined up to cross. You want to let folks know how traffic is moving on your bridge. A decent metric would be how many cars are waiting at a particular time. If no cars are waiting, incoming drivers know they can drive across right away. If cars are backed up, drivers know they're in for delays.

So, Bridge Operator, what numbering system are you going to use? How about:

  • 0.00 means there's no traffic on the bridge at all. In fact, between 0.00 and 1.00 means there's no backup, and an arriving car will just go right on.
  • 1.00 means the bridge is exactly at capacity. All is still good, but if traffic gets a little heavier, things are going to slow down.
  • over 1.00 means there's backup. How much? Well, 2.00 means that there are two lanes worth of cars total -- one lane's worth on the bridge, and one lane's worth waiting. 3.00 means there are three lane's worth total -- one lane's worth on the bridge, and two lanes' worth waiting. Etc.

 = load of 1.00

 = load of 0.50

 = load of 1.70




source:
http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages

Wednesday, November 25, 2009

python: calling a shell command

>>> import subprocess
>>> subprocess.call('ls -l $HOME', shell=True)
total 5608
-rw------- 1 root root     816 2009-10-23 18:51 anaconda-ks.cfg
drwxr-xr-x 3 root root    4096 2009-11-11 21:15 AuthPerformance
drwxr-xr-x 2 root root    4096 2009-11-04 11:34 deleteme
-rw-r--r-- 1 root root     162 2009-10-23 21:08 eth0
-rw-r--r-- 1 root root    4118 2009-10-29 18:03 gdb.txt
-rw-r--r-- 1 root root      99 2009-10-23 21:08 ifcfg-eth0
-rw-r--r-- 1 root root   21859 2009-10-23 18:51 install.log
-rw-r--r-- 1 root root    3155 2009-10-23 18:51 install.log.syslog
-rw-r--r-- 1 root root 1444369 2009-10-26 16:16 libmod_piauth.so
-rw-r--r-- 1 root root 1442766 2009-10-21 18:04 libmod_piauth.so.bkp
drwxr-xr-x 2 root root    4096 2009-11-25 17:49 mozynow
-rw-r--r-- 1 root root  218691 2009-11-19 20:52 pi-auth-2.8-122769-122769-20091119.2030.02-linux-Release.i386.rpm
-rw-r--r-- 1 root root  376900 2009-11-10 11:52 reinstall.log
drwxr-xr-x 5 root root 2146304 2009-11-04 14:28 scripts
-rw-r--r-- 1 root root     382 2009-11-18 18:07 status
-rw-r--r-- 1 root root       0 2009-11-25 17:46 status.1
drwx------ 3 root root    4096 2009-11-19 21:29 usr
0
>>>


source

debian: how to install from .deb files, while taking care of dependencies


dpkg -i <file.deb>
apt-get -f install


This will pull in all undsatisfied dependancies or removes the offending package(s)

Note: Works like a charm! Just tried it on "justniffer_0.5.6_i386.deb" from "http://justniffer.sourceforge.net/index.html".

source

Thursday, November 19, 2009

Tuesday, November 17, 2009

awk: parse a conf file having "a=b" entries

Given a config file (i.e. a text input file to a test) containing "A=B" key/value pairs like the one below:

[root@mttf ~]# head authPerf.conf
domain = mttf.appfwk.net
testidentity = appfwk1
identityNameTemplate = test
password = abcabc
adminpassword = abcdef123

PROBLEM: How can I get the RHS of each "="? In other words, how can I get the values of 'domain', 'testidentity', 'password' etc?

SOLUTION: use AWK!
[root@mttf ~]# grep "domain" authPerf.conf | awk  -F= '{gsub(/^[ \t]+/ , "", $2); print $2}'
mttf.appfwk.net

Monday, November 16, 2009

excel: how to find the first blank row/column

First blank column in the A row:
=MATCH(TRUE,ISBLANK(A2:AA2),0)


First blank row in the A column:
=MATCH(TRUE,ISBLANK(A2:A1000000),0)

yet another "To Do" list

- i have really wanted to learn CSS and webdesign, ala dreamweaver/django/rails. it affords so much scope for creativity and self-expression. always wanted to build a nice website. gotta start setting aside an hour a day towards this goal.

- gotta complete pythonchallenge.com

- write simple script to parse XML in python (required for smoke test setup)
this is what the backup script does from the /pi/hosting/status page

- maybe even finish notpron?

Thursday, October 29, 2009

windows: installing the recovery console on xp

To install the Recovery Console in Windows XP, follow these steps:


1.    Insert the Windows XP CD into the CD-ROM drive.
2.    Click Start, and then click Run.
3.    In the Open box, type d:\i386\winnt32.exe /cmdcons where d is the drive letter for the CD-ROM drive. In the case of 'Microsoft Windows XP Professional x64 Edition, type d:\amd64\winnt32.exe /cmdcons where d is the drive letter for the CD-ROM drive.
4.    A Windows Setup Dialog Box appears. The Windows Setup Dialog Box describes the Recovery Console option. To confirm the installation, click Yes.
5.    Restart the computer. The next time that you start your computer, "Microsoft Windows Recovery Console" appears on the startup menu.

Thursday, October 22, 2009

gdb: incredibly useful stuff!

For ages, I'd wanted gdb to search for the source file recursively inside a given "dir". Now I finally figured out how to accomplish this. Not by a 'recursive dir search', but by setting a 'substitute path' in gdb. This makes life so much easier now! Woohoo! :D

Much much thanks to this source for setting substitute-paths for gdb:

You know, by using a set substitute-path <library-source-path>
installed-source-path
in the $HOME/.gdbinit file it is possible to
install the library source somewhere and have gdb replace the path
where the library's debug info says the source should be with where
you've installed the library's source.

On my system, for example, by using the 'strings' command, I'm able
to see that glibmm's debug info says that the source should be found
in /build/buildd/glibmm2.4-2.14.2/. I actually installed glibmm's
source in /usr/src/glibmm2.4-2.14.2. So by including the line set
substitute-path /build/buildd /usr/src
in ~/.gdbinit, gdb has no
problems finding glibmm's source any more.

This works with all debuggers (even nemiver) as long as ~/.gdbinit is
processed by gdb when it starts up. :-)


So this is my current ~/.gdbinit file:
set substitute-path /sandbox/builds/appframework_dev /data/source/branches/appframework_dev
And I tested it on piidentity.net right away. IT'S AWESOME! Works right outta da box!

You can now automatically "list" code immedidately after attaching gdb to an httpd process - totally painlessly. This is so much better than having to set each "dir" in gdb for each source directory you wanted to "list" as you debugged it. I love "set substitute-path" - it rocks!


Some more cool gdb stuff I learnt today:
  • interpreter-exec mi "-file-list-exec-source-files"
    (which is equivalent to "info sources")
  • interpreter-exec mi "-file-list-exec-source-file"
    (which is equivalent to "info source")
  • GDB has a ncurses-based GUI called TUI mode! Whoa!
    http://sources.redhat.com/gdb/current/onlinedocs/gdb_26.html

Tuesday, October 20, 2009

windows: how to schedule a high-frequency task

Task Scheduler doesn't let you schedule tasks with fine-grained frequencies. For example, you can't schedule a task to execute every minute, or every few hours. The maximum frequency that can be given to a task is "daily" which sucks because you need to run some programs more often than that (linux's cron is still the king!)

Here's the solution. It involves using the rather powerful "schtasks" windows command:

http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/schtasks.mspx?mfr=true

Here's what I used:
schtasks /create /sc hourly /mo 2 /tn "autoupdatesourcecode" /tr c:\tools\autoupdatesourcecode.bat


And this is my super-simple autoupdatesourcecode.bat:
cd d:\Codebase\trunk\pi\
d:
svn up

Wednesday, October 14, 2009

c++: auto_ptr::release()

auto_ptr::release()

The release() function removes ownership of the stored object from the
invoking auto_ptr and returns a pointer to the object. After a call to release(),
the pointed-to object is not automatically destroyed when the auto_ptr object
goes out of scope.

 -- Herb Schildt's C++ Programming Cookbook, Chapter 7, page 489

Monday, October 12, 2009

c++: deleting elements from a map

Q: Does std::map.erase() properly delete pointers, or does it create memory leaks?

A: It properly does not delete pointers, because it can't assume that nothing else points at the same thing. std::map cleans up the memory *it* explicitly allocated. *You* clean up the memory *you* explicitly allocated.


Here's how to safely delete all elements in a map, that will work for any container:
std::map<int, char*> Mappy;

int main()
{
    for(int Index = 0; Index < 10; ++Index)
    Mappy.insert(std::make_pair(Index, new char[10]));

    for(std::map<int, char*>::iterator MapItor = Mappy.begin(); MapItor != Mappy.end(); ++MapItor)
    {
        char* Value = (*MapItor).second;
        delete Value;
    }

    system("pause");
    return 0;
}

Tuesday, October 6, 2009

batch file to fix WMI errors

There's a lot to learn about batch file scripting from this example!
source

net stop winmgmt

pause

c:

cd c:\windows\system32\wbem

rd /S /Q repository

regsvr32 /s %systemroot%\system32\scecli.dll

regsvr32 /s %systemroot%\system32\userenv.dll

mofcomp cimwin32.mof

mofcomp cimwin32.mfl

mofcomp rsop.mof

mofcomp rsop.mfl

for /f %%s in ('dir /b /s *.dll') do regsvr32 /s %%s

for /f %%s in ('dir /b *.mof') do mofcomp %%s

for /f %%s in ('dir /b *.mfl') do mofcomp %%s

mofcomp exwmi.mof

mofcomp -n:root\cimv2\applications\exchange wbemcons.mof

mofcomp -n:root\cimv2\applications\exchange smtpcons.mof

mofcomp exmgmt.mof

Monday, October 5, 2009

linux: adding swap space on-the-fly to your system

You might find that the swap partition you specified at install-time just isn't enough anymore. Maybe you've added more RAM to your machine and need to increase the swap partition accordingly. Or maybe you're upgrading your system to a version that uses more swap in relation to physical RAM. Perhaps you're running Oracle. In case your machine is swapping like mad and you just can't take it down right now to add more RAM, you can add more swap space on the fly using the following procedure. As an example, to keep the machine from running out of memory entirely and freezing up, we'll add 128 MB more swap space by creating a swap file. First we check out the memory usage:

[root@domain /root]# free -m
total used free shared buffers cached
Mem: 251 242 8 22 11 32
-/+ buffers/cache: 198 52
Swap: 133 133 0

Make sure we have 128 MB laying around somewhere:

[root@domain /root]# df
Filesystem 1k-blocks Used Available Use% Mounted on
/dev/hda9 132207 33429 91952 27% /
/dev/hda1 15522 2537 12184 17% /boot
/dev/hda6 6143236 739000 5092176 13% /opt
/dev/hda7 1035660 836204 146848 85% /usr
/dev/hda5 2071384 344048 1622112 17% /usr/local
/dev/hda8 303344 14439 273244 5% /var

OK, we're going to make a swap file in /opt by using dd to create a file 128 MB in size.

[root@domain /opt]# dd if=/dev/zero of=swapfile bs=1024 count=132207
132207+0 records in
132207+0 records out
[root@domain /opt]# ls -l
total 132364
drwxr-xr-x 20 usr-3 users 4096 May 22 10:46 usr-3
drwxr-xr-x 2 root root 16384 Feb 21 07:04 lost+found
-rw-r--r-- 1 root root 135379968 May 29 11:52 swapfile

Let's not make it world-readable...

[root@domain /opt]# chmod 600 swapfile
[root@domain /opt]# ls -l
total 132364
drwxr-xr-x 20 usr-3 users 4096 May 22 10:46 usr-3
drwxr-xr-x 2 root root 16384 Feb 21 07:04 lost+found
-rw------- 1 root root 135379968 May 29 11:52 swapfile

Now we set up the swap area and enable it.

[root@domain /opt]# mkswap swapfile
Setting up swapspace version 1, size = 135372800 bytes
[root@domain /opt]# swapon swapfile

And voila! Twice as much swap as before.

[root@domain /opt]# free
total used free shared buffers cached
Mem: 257632 254632 3000 2512 36172 15096
-/+ buffers/cache: 203364 54268
Swap: 268708 136512 132196

You can append a line like this to /etc/fstab to enable your swap file automatically at boot time:

/opt/swapfile swap swap defaults 0 0


source

Wednesday, September 23, 2009

python: writing your own urllib2 redirect_handler

class SmartRedirectHandler(urllib2.HTTPRedirectHandler):

    def redirect_request(self, req, fp, code, msg, headers, newurl=''):
        global intermediateURL
        intermediateURL = newurl

        if code in (301, 302, 303, "refresh") or (code == 307 and not req.has_data()):
            newRequest = urllib2.Request(   
                                            newurl,
                                            headers=req.headers,
                                            origin_req_host=req.get_origin_req_host(),
                                            unverifiable=True
                                        )
            newRequest._origin_req = getattr(req, "_origin_req", req)
            
        return newRequest
        
        else:
            raise HTTPError(req.get_full_url(), code, msg, headers, fp)

source

Tuesday, September 15, 2009

how to enable tap zones on dell mouse drivers

To unlock the native touchpad features which are masked by Dell's touchpad software:

1. Go to control panel and select MOUSE to see what options are available (very few) and close that all up.

2. Next click on the Windows Start icon and type regedit in the search box.
Windows Registry will open.

Navigate to HKEY_LOCALMACHINE\SOFTWARE\Alps\Apoint and look for the key UseCustomGUI (it's the 2nd to last entry on the list)

Change the value from 1 to 0 and click on OK

3. Next minimize the registry (don't close it yet).
Goto Control Panel and select MOUSE.
Now all the ALPs settings are unlocked and appear here.

For example the GESTURES feature is now showing.
Select GESTURES tab and check ON the box for
Use Back/Forward Buttons.
Then click APPLY and OK.
Close the Mouse settings and close the Control panel.

4. Now go back to your registry setting and change
UseCustomGUI back to it's original value of 1 and close it and the reg editor.

Everything is back exactly as it was but the feature remains enabled.

All done....now when your surfing just swipe your finger along the top edge of the touch pad to go back and forward.


source

Monday, September 14, 2009

vbscript: create system restore points with no fuss

Here's how to create a simple VBscript that will create a restore point when you double-click it:

1. Save the code below to, say, c:\system_restore.vbs:

Set SRP = GetObject( "winmgmts:\\.\root\default:Systemrestore" )
CSRP = SRP.CreateRestorePoint( "Before Changes", 0, 100 )

2. Double-click the script file you just created, any time you want to create a fresh System Restore Point.

It only takes a few seconds to do this. And no dialogues are shown to confirm that a Restore Point was created. If you want to double-check you can click "Start | All Programs | Accessories | System Tools | System Restore" and click "Restore My Computer To An Earlier Time."

You'll see the restore point you just created (called "Before Changes") right there. Now be sure to cancel out of System Restore.

source

Tuesday, August 25, 2009

linux: creating and using arrays in shell scripts

Bash arrays have numbered indexes only, but they are sparse, i.e. you don't have to define all the indexes.

An entire array can be assigned by enclosing the array items in parenthesis:
arr=(Hello World)

Individual items can be assigned with the familiar array syntax (unless you're used to Basic or Fortran):
arr[0]=Hello
arr[1]=World


But it gets a bit ugly when you want to refer to an array item:
echo ${arr[0]} ${arr[1]}

To quote from the man page:

The braces are required to avoid conflicts with pathname expansion.

In addition the following funky constructs are available:
${arr[*]};  # All of the items in the array
${!arr[*]}; # All of the indexes in the array
${#arr[*]}; # Number of items in the array
${#arr[0]}; # Length of item zero

The ${!arr[*]} is a relatively new addition to bash, it was not part of the original array implementation.

source

Monday, August 24, 2009

vim: commenting-out lines of code esaily

For short ranges of basic prefixing comments (# or //), I've become fond of vim's visual block mode and block insert. To do this:
  1. start visual block mode (with Ctrl-V)
  2. adjust the selection with movement keys as needed. (marks can be used here)
  3. once the selections are made, start block insert with 'I' (or append with 'A')
    NOTE: don't use the usual lowercase 'i' or 'a'
  4. type the comment text (e.g. "#")
  5. when you hit escape, comments will be added to all selected lines

source

Tuesday, August 11, 2009

nice quote about indesign

Adobe has always said that InDesign is “the future of page layout”—but we think they’re selling themselves a bit short. With InDesign, the future is here today.

And, to our eyes, at least, it looks pretty cool.

source: "Real World Adobe InDesign CS4" (Kvern and Blatner)

Monday, August 3, 2009

linux: rename multiple files with one command

We're going to do this simple task with a simple regex find+replace in sed:

for i in *.avi
do
    j=`echo $i | sed 's/mymovies/myflicks/g'`
    mv "$i" "$j"
done

Can also be written on a single line as:
for i in *.avi; do j=`echo $i | sed 's/find/replace/g'`; mv "$i" "$j"; done

source

Monday, June 8, 2009

linux: setting your machine's hostname properly

To setup the hostname manually on a Fedora or RedHat box, you need to edit two files:
  • /etc/sysconfig/network
  • /etc/hosts
1.  In the /etc/sysconfig/network file, modify the hostname:
NETWORKING=yes
HOSTNAME=fedora.hacking.com
GATEWAY=10.7.0.1
  2.  In the /etc/hosts file, modify the hostname:
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1 fedora.hacking.com fedora localhost.localdomain localhost

After making these changes to these files, the changes to the hostname should be permanent ( i.e. it will persist even across reboots). Otherwise, simply setting the hostname with the "hostname" command only affects the current session, and you lose the hostname change after the next machine reboot.

Wednesday, June 3, 2009

linux basics: ${var} vs $var

The "$" character introduces parameter expansion, command substitution, or arithmetic expansion. The parameter name or symbol to be expanded may be enclosed in braces, which are optional but serve to protect the variable to be expanded from characters immediately following it which could be interpreted as part of the name.

The basic form of parameter expansion is "${PARAMETER}". The value of "PARAMETER" is substituted. The braces are required when "PARAMETER" is a positional parameter with more than one digit, or when "PARAMETER" is followed by a character that is not to be interpreted as part of its name.

In other word, as a safety measure, always prefer ${var} over $var in your shell scripts.

source

Wednesday, May 27, 2009

c++: regular expression tester with boost

#include 
#include 
#include   // point this to your Boost.Regex lib

using namespace std;

int main( ) 
{
    std::string s, sre;
    boost::regex re;

    while(true)
    {
        cout << "Expression: ";
        cin >> sre;
        if (sre == "quit")
        {
            break;
        }
        cout << "String:     ";
        cin >> s;

        try
        {
            // Set up the regular expression for case-insensitivity
            re.assign(sre, boost::regex_constants::icase);
        }
        catch (boost::regex_error& e)
        {
            cout << sre << " is not a valid regular expression: \""
            << e.what() << "\"" << endl;
            continue;
        }
        if (boost::regex_match(s, re))
        {
            cout << re << " matches " << s << endl;
        }
    }
}

apache: worker vs prefork models

Apache's Prefork Model

This Multi-Processing Module (MPM) implements a non-threaded, pre-forking web server that handles requests in a manner similar to Apache 1.3. It is appropriate for sites that need to avoid threading for compatibility with non-thread-safe libraries. It is also the best MPM for isolating each request, so that a problem with a single request will not affect any other.
[http://httpd.apache.org/docs/2.0/mod/prefork.html]



Apache's Worker Model

Multi-Processing Module (MPM) implements a hybrid multi-threaded multi-process web server.
This Multi-Processing Module (MPM) implements a hybrid multi-process multi-threaded server. By using threads to serve requests, it is able to serve a large number of requests with less system resources than a process-based server. Yet it retains much of the stability of a process-based server by keeping multiple processes available, each with many threads.

The most important directives used to control this MPM are ThreadsPerChild, which controls the number of threads deployed by each child process and MaxClients, which controls the maximum total number of threads that may be launched.
[http://httpd.apache.org/docs/2.0/mod/worker.html]




For example, sites that need a great deal of scalability can choose to use a threaded MPM like worker, while sites requiring stability or compatibility with older software can use a prefork.
[http://httpd.apache.org/docs/2.0/mpm.html]


I compiled 2 different versions of apache 2.2.4 on Solaris 10 (06/06, on a crappy U10, but...) one using the prefork MPM (compile --with-mpm=prefork) and the other using the worker MPM (compile --with-mpm=worker). Prefork is supposed to generally be better for single or dual cpu systems, and worker is supposed to be generally better for multi-CPU systems.

So for this setup, the worker MPM was almost twice as fast as the prefork.
I'm going to run these same tests on a multi-cpu server and see what the results look like.
[http://www.camelrichard.org/apache-prefork-vs-worker]




On most Unixes, the worker MPM results in considerable performance enhancements over the prefork MPM, and it results in much greater scalability, since threads are a lot cheaper (less memory and CPU to create and run) than forked processes.
[http://www.onlamp.com/pub/a/apache/2004/06/17/apacheckbk.html]

Tuesday, May 26, 2009

c++: a simple boost::regex example

void piMozyAuthUnitTest::testBoostRegex1()
{
    std::string s, sre;
    boost::regex re;
    boost::cmatch matches;

    while(true)
    {
        cout << "Expression: ";
        cin >> sre;
        if (sre == "quit")
            break;
        

        cout << "String:     ";
        cin >> s;

        try
        {
            // Assignment and construction initialize the FSM used
            // for regexp parsing
            re = sre;
        }
        catch (boost::regex_error& e)
        {
            cout << sre << " is not a valid regular expression: \""
            << e.what() << "\"" << endl;
            continue;
        }
        // if (boost::regex_match(s.begin(), s.end(), re))
        if (boost::regex_match(s.c_str(), matches, re))
        {
            // matches[0] contains the original string.  matches[n]
            // contains a sub_match object for each matching
            // subexpression
            for (int i = 1; i < matches.size(); i++)
            {
                // sub_match::first and sub_match::second are iterators that
                // refer to the first and one past the last chars of the
                // matching subexpression
                string match(matches[i].first, matches[i].second);
                cout << "\tmatches[" << i << "] = " << match << endl;
            }
        }
        else
        {
            cout << "The regexp \"" << re << "\" does not match \"" << s << "\"" << endl;
        }
    }

}

c++ : simple string substitution using find_first_of() and replace()

// loginURL: replace "id" with "auth" in hostname (so that "id.domain" becomes "auth.domain")
// tested and working!

string x = loginURL; 
size_t pos1 = x.find_first_of("//") + 2;
size_t pos2 = x.find_first_of(".");
size_t len = pos2-pos1;

x.replace(pos1, len, "auth");

Saturday, February 7, 2009

watchShutdownLogs.pl

I wrote this little script that really helps with testing dynamic store loading:

INVOKE AS:
watch -n 2 --differences=cumulative 'perl /root/watchShutdownLogs'



#!/usr/bin/perl


@fileList = `find /usr/local/pi/hosting/data/*/config/shutdown.pinode.conf`;
foreach $x (@fileList)
{
$x =~ m/data\/(.+)\/config/;
$y = $1;
print "$y \n";

printFile($x);
print "\n";

}


sub printFile
{
my $filename = $_[0];

open( FILE, $filename ) or die "Can't open $filename : $!";

while( ) {
if (m/store/)
{print $_;}
}

close FILE;
}

Tuesday, January 13, 2009

c++: const pointer and pointer to const

For pointer and reference types, the syntax is slightly more subtle. A pointer object can be declared as a const pointer or a pointer to a const object (or both).

A const pointer cannot be reassigned to point to a different object from the one it is initially assigned, but it can be used to modify the object that it points to (called the "pointee"). (Reference variables are thus an alternate syntax for const pointers.)

A pointer to a const object, on the other hand, can be reassigned to point to another object of the same type or of a convertible type, but it cannot be used to modify any object.

A const pointer to a const object can also be declared and can neither be used to modify the pointee nor be reassigned to point to another object.

The following code illustrates these subtleties:

void Foo( int * ptr, int const * ptrToConst, int * const constPtr, int const * const constPtrToConst )
{ 
    *ptr = 0; // OK: modifies the pointee

    ptr = 0; // OK: modifies the pointer

    *ptrToConst = 0; // Error! Cannot modify the pointee

    ptrToConst = 0; // OK: modifies the pointer

    *constPtr = 0; // OK: modifies the pointee

    constPtr = 0; // Error! Cannot modify the pointer

    *constPtrToConst = 0; // Error! Cannot modify the pointee

    constPtrToConst = 0; // Error! Cannot modify the pointer 
}
source