Use backtick code blocks for syntax highlighting
This commit is contained in:
parent
8ed9dea394
commit
f658bfbb40
203 changed files with 26546 additions and 25801 deletions
266
08-05.md
266
08-05.md
|
|
@ -20,149 +20,155 @@ merely rearranged.
|
|||
|
||||
**LISTING 8.5 L8-5.C**
|
||||
|
||||
/* Program to search an array spanning a linked list of variable-
|
||||
sized blocks, for all entries with a specified ID number,
|
||||
and return the average of the values of all such entries. Each of
|
||||
the variable-sized blocks may contain any number of data entries,
|
||||
stored in the form of two separate arrays, one for ID numbers and
|
||||
one for values. */
|
||||
```c
|
||||
/* Program to search an array spanning a linked list of variable-
|
||||
sized blocks, for all entries with a specified ID number,
|
||||
and return the average of the values of all such entries. Each of
|
||||
the variable-sized blocks may contain any number of data entries,
|
||||
stored in the form of two separate arrays, one for ID numbers and
|
||||
one for values. */
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef __TURBOC__
|
||||
#include <alloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef __TURBOC__
|
||||
#include <alloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
void main(void);
|
||||
void exit(int);
|
||||
extern unsigned int FindIDAverage2(unsigned int,
|
||||
struct BlockHeader *);
|
||||
void main(void);
|
||||
void exit(int);
|
||||
extern unsigned int FindIDAverage2(unsigned int,
|
||||
struct BlockHeader *);
|
||||
```
|
||||
|
||||

|
||||
|
||||
/* Structure that starts each variable-sized block */
|
||||
struct BlockHeader {
|
||||
struct BlockHeader *NextBlock; /* Pointer to next block, or NULL
|
||||
if this is the last block in the
|
||||
linked list */
|
||||
unsigned int BlockCount; /* The number of DataElement entries
|
||||
in this variable-sized block */
|
||||
};
|
||||
```c
|
||||
/* Structure that starts each variable-sized block */
|
||||
struct BlockHeader {
|
||||
struct BlockHeader *NextBlock; /* Pointer to next block, or NULL
|
||||
if this is the last block in the
|
||||
linked list */
|
||||
unsigned int BlockCount; /* The number of DataElement entries
|
||||
in this variable-sized block */
|
||||
};
|
||||
|
||||
void main(void) {
|
||||
int i,j;
|
||||
unsigned int IDToFind;
|
||||
struct BlockHeader *BaseArrayBlockPointer,*WorkingBlockPointer;
|
||||
int *WorkingDataPointer;
|
||||
struct BlockHeader **LastBlockPointer;
|
||||
void main(void) {
|
||||
int i,j;
|
||||
unsigned int IDToFind;
|
||||
struct BlockHeader *BaseArrayBlockPointer,*WorkingBlockPointer;
|
||||
int *WorkingDataPointer;
|
||||
struct BlockHeader **LastBlockPointer;
|
||||
|
||||
printf("ID # for which to find average: ");
|
||||
scanf("%d",&IDToFind);
|
||||
printf("ID # for which to find average: ");
|
||||
scanf("%d",&IDToFind);
|
||||
|
||||
/* Build an array across 5 blocks, for testing */
|
||||
/* Anchor the linked list to BaseArrayBlockPointer */
|
||||
LastBlockPointer = &BaseArrayBlockPointer;
|
||||
/* Create 5 blocks of varying sizes */
|
||||
for (i = 1; i < 6; i++) {
|
||||
/* Try to get memory for the next block */
|
||||
if ((WorkingBlockPointer =
|
||||
(struct BlockHeader *) malloc(sizeof(struct BlockHeader) +
|
||||
sizeof(int) * 2 * i * 10)) == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
/* Set the number of data elements in this block */
|
||||
WorkingBlockPointer->BlockCount = i * 10;
|
||||
/* Link the new block into the chain */
|
||||
*LastBlockPointer = WorkingBlockPointer;
|
||||
/* Point to the first data field */
|
||||
WorkingDataPointer = (int *) ((char *)WorkingBlockPointer +
|
||||
sizeof(struct BlockHeader));
|
||||
/* Fill the data fields with ID numbers and values */
|
||||
for (j = 0; j < (i * 10); j++, WorkingDataPointer++) {
|
||||
*WorkingDataPointer = j;
|
||||
*(WorkingDataPointer + i * 10) = i * 1000 + j;
|
||||
}
|
||||
/* Remember where to set link from this block to the next */
|
||||
LastBlockPointer = &WorkingBlockPointer->NextBlock;
|
||||
}
|
||||
/* Set the last block's "next block" pointer to NULL to indicate
|
||||
that there are no more blocks */
|
||||
WorkingBlockPointer->NextBlock = NULL;
|
||||
printf("Average of all elements with ID %d: %u\n",
|
||||
IDToFind, FindIDAverage2(IDToFind, BaseArrayBlockPointer));
|
||||
exit(0);
|
||||
}
|
||||
/* Build an array across 5 blocks, for testing */
|
||||
/* Anchor the linked list to BaseArrayBlockPointer */
|
||||
LastBlockPointer = &BaseArrayBlockPointer;
|
||||
/* Create 5 blocks of varying sizes */
|
||||
for (i = 1; i < 6; i++) {
|
||||
/* Try to get memory for the next block */
|
||||
if ((WorkingBlockPointer =
|
||||
(struct BlockHeader *) malloc(sizeof(struct BlockHeader) +
|
||||
sizeof(int) * 2 * i * 10)) == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
/* Set the number of data elements in this block */
|
||||
WorkingBlockPointer->BlockCount = i * 10;
|
||||
/* Link the new block into the chain */
|
||||
*LastBlockPointer = WorkingBlockPointer;
|
||||
/* Point to the first data field */
|
||||
WorkingDataPointer = (int *) ((char *)WorkingBlockPointer +
|
||||
sizeof(struct BlockHeader));
|
||||
/* Fill the data fields with ID numbers and values */
|
||||
for (j = 0; j < (i * 10); j++, WorkingDataPointer++) {
|
||||
*WorkingDataPointer = j;
|
||||
*(WorkingDataPointer + i * 10) = i * 1000 + j;
|
||||
}
|
||||
/* Remember where to set link from this block to the next */
|
||||
LastBlockPointer = &WorkingBlockPointer->NextBlock;
|
||||
}
|
||||
/* Set the last block's "next block" pointer to NULL to indicate
|
||||
that there are no more blocks */
|
||||
WorkingBlockPointer->NextBlock = NULL;
|
||||
printf("Average of all elements with ID %d: %u\n",
|
||||
IDToFind, FindIDAverage2(IDToFind, BaseArrayBlockPointer));
|
||||
exit(0);
|
||||
}
|
||||
```
|
||||
|
||||
**LISTING 8.6 L8-6.ASM**
|
||||
|
||||
; Alternative optimized assembly language version of FindIDAverage
|
||||
; requires data organized as two arrays within each block rather
|
||||
; than as an array of two-value element structures. This allows the
|
||||
; use of REP SCASW for ID searching.
|
||||
```asm
|
||||
; Alternative optimized assembly language version of FindIDAverage
|
||||
; requires data organized as two arrays within each block rather
|
||||
; than as an array of two-value element structures. This allows the
|
||||
; use of REP SCASW for ID searching.
|
||||
|
||||
SearchedForIDequ4 ;Passed parameter offsets in the
|
||||
BlockPointerequ6 ; stack frame (skip over pushed BP
|
||||
; and the return address)
|
||||
NextBlockequ0 ;Field offsets in struct BlockHeader
|
||||
BlockCountequ2
|
||||
BLOCK_HEADER_SIZEequ4 ;Number of bytes in struct BlockHeader
|
||||
SearchedForIDequ4 ;Passed parameter offsets in the
|
||||
BlockPointerequ6 ; stack frame (skip over pushed BP
|
||||
; and the return address)
|
||||
NextBlockequ0 ;Field offsets in struct BlockHeader
|
||||
BlockCountequ2
|
||||
BLOCK_HEADER_SIZEequ4 ;Number of bytes in struct BlockHeader
|
||||
|
||||
.model small
|
||||
.code
|
||||
public _FindIDAverage2
|
||||
_FindIDAverage2 proc near
|
||||
push bp ;Save caller's stack frame
|
||||
mov bp,sp ;Point to our stack frame
|
||||
push di ;Preserve C register variables
|
||||
push si
|
||||
mov di,ds ;Prepare for SCASW
|
||||
mov es,di
|
||||
cld
|
||||
mov si,[bp+BlockPointer] ;Pointer to first block
|
||||
mov ax,[bp+SearchedForID] ;ID we're looking for
|
||||
sub dx,dx ;IDMatchSum = 0
|
||||
mov bp,dx ;IDMatchCount = 0
|
||||
;***stack frame no longer available***
|
||||
; Search through all the linked blocks until the last block
|
||||
; (marked with a NULL pointer to the next block) has been searched.
|
||||
BlockLoop:
|
||||
; Search through all the DataElement entries within this block
|
||||
; and accumulate data from all that match the desired ID.
|
||||
mov cx,[si+BlockCount]
|
||||
jcxz DoNextBlock;Skip this block if there's no data
|
||||
; to search through
|
||||
mov bx,cx ;We'll use BX to point to the
|
||||
shl bx,1 ; corresponding value entry in the
|
||||
; case of an ID match (BX is the
|
||||
; length in bytes of the ID array)
|
||||
; Point to the first DataElement entry within this block.
|
||||
lea di,[si+BLOCK_HEADER_SIZE]
|
||||
IntraBlockLoop:
|
||||
repnz scasw ;Search for the ID
|
||||
jnz DoNextBlock ;No match, the block is done
|
||||
inc bp ;We have a match; IDMatchCount++;
|
||||
add dx,[di+bx-2];IDMatchSum += DataPointer->Value;
|
||||
; (SCASW has advanced DI 2 bytes)
|
||||
and cx,cx ;Is there more data to search through?
|
||||
jnz IntraBlockLoop ;yes
|
||||
; Point to the next block and continue if that pointer isn't NULL.
|
||||
DoNextBlock:
|
||||
mov si,[si+NextBlock] ;Get pointer to the next block
|
||||
and si,si ;Is it a NULL pointer?
|
||||
jnz BlockLoop ;No, continue
|
||||
; Calculate the average of all matches.
|
||||
sub ax,ax ;Assume we found no matches
|
||||
and bp,bp
|
||||
jz Done ;We didn't find any matches, return 0
|
||||
xchg ax,dx ;Prepare for division
|
||||
div bp ;Return IDMatchSum / IDMatchCount
|
||||
Done: pop si ;Restore C register variables
|
||||
pop di
|
||||
pop bp ;Restore caller's stack frame
|
||||
ret
|
||||
_FindIDAverage2 ENDP
|
||||
end
|
||||
.model small
|
||||
.code
|
||||
public _FindIDAverage2
|
||||
_FindIDAverage2 proc near
|
||||
push bp ;Save caller's stack frame
|
||||
mov bp,sp ;Point to our stack frame
|
||||
push di ;Preserve C register variables
|
||||
push si
|
||||
mov di,ds ;Prepare for SCASW
|
||||
mov es,di
|
||||
cld
|
||||
mov si,[bp+BlockPointer] ;Pointer to first block
|
||||
mov ax,[bp+SearchedForID] ;ID we're looking for
|
||||
sub dx,dx ;IDMatchSum = 0
|
||||
mov bp,dx ;IDMatchCount = 0
|
||||
;***stack frame no longer available***
|
||||
; Search through all the linked blocks until the last block
|
||||
; (marked with a NULL pointer to the next block) has been searched.
|
||||
BlockLoop:
|
||||
; Search through all the DataElement entries within this block
|
||||
; and accumulate data from all that match the desired ID.
|
||||
mov cx,[si+BlockCount]
|
||||
jcxz DoNextBlock;Skip this block if there's no data
|
||||
; to search through
|
||||
mov bx,cx ;We'll use BX to point to the
|
||||
shl bx,1 ; corresponding value entry in the
|
||||
; case of an ID match (BX is the
|
||||
; length in bytes of the ID array)
|
||||
; Point to the first DataElement entry within this block.
|
||||
lea di,[si+BLOCK_HEADER_SIZE]
|
||||
IntraBlockLoop:
|
||||
repnz scasw ;Search for the ID
|
||||
jnz DoNextBlock ;No match, the block is done
|
||||
inc bp ;We have a match; IDMatchCount++;
|
||||
add dx,[di+bx-2];IDMatchSum += DataPointer->Value;
|
||||
; (SCASW has advanced DI 2 bytes)
|
||||
and cx,cx ;Is there more data to search through?
|
||||
jnz IntraBlockLoop ;yes
|
||||
; Point to the next block and continue if that pointer isn't NULL.
|
||||
DoNextBlock:
|
||||
mov si,[si+NextBlock] ;Get pointer to the next block
|
||||
and si,si ;Is it a NULL pointer?
|
||||
jnz BlockLoop ;No, continue
|
||||
; Calculate the average of all matches.
|
||||
sub ax,ax ;Assume we found no matches
|
||||
and bp,bp
|
||||
jz Done ;We didn't find any matches, return 0
|
||||
xchg ax,dx ;Prepare for division
|
||||
div bp ;Return IDMatchSum / IDMatchCount
|
||||
Done: pop si ;Restore C register variables
|
||||
pop di
|
||||
pop bp ;Restore caller's stack frame
|
||||
ret
|
||||
_FindIDAverage2 ENDP
|
||||
end
|
||||
```
|
||||
|
||||
The whole point of this rearrangement is to allow us to use **REP
|
||||
SCASW** to search through each block, and that's exactly what
|
||||
|
|
|
|||
Loading…
Reference in a new issue