Tuesday, March 17, 2020

Understanding and Using Pointers in Delphi

Understanding and Using Pointers in Delphi Even though pointers arent as important in Delphi as they are in C or C, theyre such a basic tool that almost anything having to do with programming must deal with pointers in some fashion. Its for that reason that you might read about how a string or object is really just a pointer, or that an event handler such as OnClick, is actually a pointer to a procedure. Pointer to Data Type Simply put, a pointer is a variable that holds the address of anything in memory. To concrete this definition, keep in mind that everything used by an application is stored somewhere in the computers memory. Because a pointer holds the address of another variable, its said to point to that variable. Most of the time, pointers in Delphi point to a specific type: variValue, j : integer;pIntValue : ^integer;beginiValue : 2001;pIntValue : iValue;...j: pIntValue^;end; The syntax to declare a pointer data type uses a caret (^). In the above code, iValue is an integer type variable and pIntValue is an integer type pointer. Since a pointer is nothing more than an address in memory, we must assign to it the location (address) of the value stored in the iValue integer variable. The operator returns the address of a variable (or a function or procedure as will be seen below). Equivalent to the operator is Addr function. Note that pIntValues value is not 2001. In this sample code, pIntValue is a typed integer pointer. Good programming style is to use typed pointers as much as you can. The Pointer data type is a generic pointer type; it represents a pointer to any data. Note that when ^ appears after a pointer variable, it de-references the pointer; that is, it returns the value stored at the memory address held by the pointer. In this example, variable j has the same value as iValue. It might look like this has no purpose when we can simply assign iValue to j, but this piece of code lies behind most calls to Win API. NILing Pointers Unassigned pointers are dangerous. Since pointers let us work directly with computers memory, if we try to (by mistake) write to a protected location in memory, we could get an access violation error. This is the reason we should always initialize a pointer to NIL. NIL is a special constant that can be assigned to any pointer. When nil is assigned to a pointer, the pointer doesn’t reference anything. Delphi presents, for example, an empty dynamic array or a long string as a nil pointer. Character Pointers The fundamental types PAnsiChar and PWideChar represent pointers to AnsiChar and WideChar values. The generic PChar represents a pointer to a Char variable. These character pointers are used to manipulate null-terminated strings. Think of a PChar as being a pointer to a null-terminated string or to the array that represents one. Pointers to Records When we define a record or other data type, its a common practice also to define a pointer to that type. This makes it easy to manipulate instances of the type without copying large blocks of memory. The ability to have pointers to records (and arrays) makes it much easier to set up complicated data structures as linked lists and trees. typepNextItem ^TLinkedListItemTLinkedListItem recordsName : String;iValue : Integer;NextItem : pNextItem;end; The idea behind linked lists is to give us the possibility to store the address to the next linked item in a list inside a NextItem record field. Pointers to records can also be used when storing custom data for every tree view item, for example. Procedural and Method Pointers Another important pointer concept in Delphi is procedure and method pointers. Pointers that point to the address of a procedure or function are called procedural pointers. Method pointers are similar to procedure pointers. However, instead of pointing to standalone procedures, they must point to class methods. Method pointer is a pointer that contains information about both the name and object thats being invoked. Pointers and Windows API The most common use for pointers in Delphi is interfacing to C and C code, which includes accessing the Windows API. Windows API functions use a number of data types that might be unfamiliar to the Delphi programmer. Most of the parameters in calling API functions are pointers to some data type. As stated above, we use null-terminated strings in Delphi when calling Windows API functions. In many cases, when an API call returns a value in a buffer or pointer to a data structure, these buffers and data structures must be allocated by the application before the API call is made. The SHBrowseForFolder Windows API function is one example. Pointer and Memory Allocation The real power of pointers comes from the ability to set aside memory while the program is executing. This piece of code should be enough to prove that working with pointers is not as hard as it might seem at first. Its used to change the text (caption) of the control with the Handle provided. procedure GetTextFromHandle(hWND: THandle) ;var pText : PChar; //a pointer to char (see above)TextLen : integer;begin{get the length of the text}TextLen:GetWindowTextLength(hWND) ;{alocate memory}GetMem(pText,TextLen) ; // takes a pointer{get the controls text}GetWindowText(hWND, pText, TextLen 1) ;{display the text}ShowMessage(String(pText)){free the memory}FreeMem(pText) ;end;

Sunday, March 1, 2020

Reconsider Planting Leyland Cypress in Your Yard

Reconsider Planting Leyland Cypress in Your Yard The rapidly-growing Leyland cypress tree, or  Cupressocyparis leylandii,  quickly outgrows its space in a typical yard, unless properly and regularly trimmed. These trees have the potential to grow to 60 feet tall. They are not a practical tree to plant as a small yard hedge on tight, six- to eight-foot  centers. Tight spacing of the plant means that you must commit major time and effort to constant pruning. Leyland cypress is a  short-lived conifer, with a typical lifespan of 20 to 25 years, and will eventually have to be removed. Even properly-spaced trees left to grow may have limited root support, and are subject to being blown down during high winds if planted on wet soils. Consider the work needed to maintain a Leyland cypress before planting one. Why Not Plant Leyland Cypress? A study of Leyland cypress done at the University of Tennessee indicated that a lot of damage on these trees is simply environmental, and not always directly caused by a disease or insect. The study indicated that stress from a harsh winter can cause sporadic limb die off among Leyland cypress trees. Leyland cypresses grow into large, mature trees at 60-plus feet tall with a potential 20-plus foot spread. When they are planted as hedges on tight centers less of than 10 feet, there will be a major competitive  struggle for nutrients and shading. When needles turn brown or drop, the tree is reacting to environmental stresses. Leyland cypress trees do not tolerate many diseases and insects well, especially when environmental stressors are present. Spacing and soil may create an environment that can cause future stress on these trees. Planting Leyland cypress too close together or too close to other trees and structures that shade them can decrease vigor and increase pest damage. Caring for an Existing Tree Eliminating moisture stress on Leyland cypress through watering techniques can help lessen the occurrence of canker diseases. In particular, Leyland cypress is susceptible to Seiridium canker. There is no control for this disease other than to prune out the infected plant part. Watering is a long-term commitment for the Leyland cypress owner. These trees should be watered during any period of dry weather and should receive at least 1 inch of water per week. Pour the water at the base of the tree, and do not spray water on the foliage with sprinklers or watering techniques that can cause various  tree disease. As these tree age and lose lower foliage, consider removing Leyland cypress individually as they deteriorate, and replace each with a deciduous evergreen tree like wax myrtle.