Programming, Problem Solving



Download 0.51 Mb.
Page5/6
Date05.08.2017
Size0.51 Mb.
#26659
1   2   3   4   5   6

7.6

Character

String Processing

At this point, we have sufficient skills to create our own versions of the string utilities found in string.h. User-friendly interactive programming provides many opportunities to do character manipulation.



Example 7.18

Let us create a function StrCpy. Our version of the function will have no explicit return. It will place the NewString in the String. We shall pass the size of the container to prevent overflow. We shall begin with a main program which declares a ten-character string variable called Name.





char

Name [10];

int

Index;



We plan to test our StrCpy function on Name. Since it currently contains garbage, let us fill the string with known information (Perhaps A,B,C,...).





for (Index = 0; Index < sizeof (Name); Index ++)

Name[Index]=Index+65;





The following code fragment can be used


for (Index = 0; Index < sizeof (Name); Index ++)

printf ("%2d -> %c [%3d]\n",Index,Name[Index],Name[Index]);


to display the contents of Name.




0 -> A [ 65]

1 -> B [ 66]

2 -> C [ 67]

3 -> D [ 68]

4 -> E [ 69]

5 -> F [ 70]

6 -> G [ 71]

7 -> H [ 72]

8 -> I [ 73]

9 -> J [ 74]




We have to remember to leave room for the end of string marker. The basic logic for StrCpy is
1. Set Pos to 0

2. While the next character to copy is not the end of string marker and

there are still more characters left in the original string

2.1 Copy NewString[Pos] into String[Pos]

2.2 Increment Pos

3. Put and end-of-string marker in String.


There are many solutions to this problem. One of the solutions is
void StrCpy1 (char String[], char NewString[],long int MaxChars)

{

long int



Pos;

for (Pos = 0; NewString[Pos] && Pos < MaxChars -1 ; Pos ++)

String[Pos] = NewString[Pos];

String[Pos]=0;

}
Since the NewString contains only eight characters, there is no need to alter more than eight characters of the String. Name[9] still contains the original 'J'. Since printf and puts print only until the end-of-string marker is found, the 'J' is never printed.

If StrCpy1 were evoked with




StrCpy1 (Name, "Abe Linc", sizeof (Name));

for (Index = 0; Index < sizeof (Name)+3; Index ++)

printf ("%2d -> %c [%3d]\n",Index,Name[Index],Name[Index]);


then the following output could be generated.

0 -> A [ 65]

1 -> b [ 98]

2 -> e [101]

3 -> [ 32]

4 -> L [ 76]

5 -> i [105]

6 -> n [110]

7 -> k [107]

8 -> [ 0]

9 -> J [ 74]

Another working version is found in StrCpy2.


void StrCpy2 (char String[], char NewString[],long int MaxChars)

{

long int



Pos = 0;

while ( ( Pos < MaxChars-1 ) && ( NewString[Pos] != 0 ) )

{

String[Pos] = NewString[Pos];



Pos ++;

}

String[Pos]=0;



}
Example 7.19

Let us create a function StrLen. Our version of the function will explicitly return a long integer indicating the number of characters in the original string. Once more we shall use the main program which declares a ten-character string variable called Name.


long int StrLen1 (char String[])

{

long int



Pos,

Count;


for ( Pos = 0, Count = 0 ; String[Pos]; Pos ++, Count++);

return (Count);

}
If StrLen1 and StrCpy1 were evoked with


StrCpy1 (Name, "", sizeof (Name));

printf ("String [%s] has %lu characters\n",Name,StrLen1(Name));

StrCpy1 (Name, "Tex", sizeof (Name));

printf ("String [%s] has %lu characters\n",Name,StrLen1(Name));

StrCpy1 (Name, "Texas Rangers", sizeof (Name));

printf ("String [%s] has %lu characters\n",Name,StrLen1(Name));


then the following output could be generated.




String [] has 0 characters

String [Tex] has 3 characters

String [Texas Ran] has 9 characters

The code fragment above helps to thoroughly test both StrLen1 and StrLen1. Notice that first call passes the "Null String", sometimes called the empty string. The second call passes a string that can easily fit in a ten-character container. The third call passes a string which exceeds ten characters; note that our StrLen1 function has prevented the string overflow which can occur with the normal strcpy function. Many of the string function solutions can use pointer arithmetic; such an alternative StrLen2 function is found below.


long int StrLen2 (char *Ptr)

{

long int



Count = 0;

while ((*Ptr) != '\0')

{

Count++;


Ptr++;

}

return (Count);



}
If StrLen2 and StrCpy2 were evoked with


StrCpy2 (Name, "", sizeof (Name));

printf ("String [%s] has %lu characters\n",Name,StrLen2(Name));

StrCpy2 (Name, "Tex", sizeof (Name));

printf ("String [%s] has %lu characters\n",Name,StrLen2(Name));

StrCpy2 (Name, "Texas Rangers", sizeof (Name));

printf ("String [%s] has %lu characters\n",Name,StrLen2(Name));




then the following output could be generated.

String [] has 0 characters

String [Tex] has 3 characters

String [Texas Ran] has 9 characters




Example 7.20

There are times that we would like the user to fill a character string with a collection of integers. Let us create a function IsIntString1 which explicitly returns True if (1) the string includes only the characters '0' - '9' and (2) the string is no more than four characters in length; otherwise return False.


boolean IsIntStr1 (char String[])

{

long int



Pos = 0;

if ((strlen (String) > 4) || (String[0] == '\0')) /* Empty String Not Valid */

return (False); /* >4 Characters Not Valid */

while (String[Pos])

{

if ((String[Pos] < '0') || (String[Pos] > '9'))



return (False);

else


Pos++;

}

if (String[Pos]) /* If Last Character Examined Not The End-Of-String Marker */



return (False); /* Then The String Is Not Valid */

else


return (True);

}
If IsIntStr1 were evoked with




do

{

printf ("Enter an Integer String <999 to Exit> : ");



gets(NoString);

if (IsIntStr1(NoString))

printf ("--> %s - Valid Integer String\n\n",NoString);

else


printf ("--> [%s] - Not Valid Integer String\n\n",NoString);

} while (strcmp (NoString, "999") != 0);





then the following output could be generated.

Enter an Integer String <999 to Exit> :

--> [] - Not Valid Integer String
Enter an Integer String <999 to Exit> : 123l2

--> [123l2] - Not Valid Integer String


Enter an Integer String <999 to Exit> : -12

--> [-12] - Not Valid Integer String


Enter an Integer String <999 to Exit> : 12345

--> [12345] - Not Valid Integer String


Enter an Integer String <999 to Exit> : 1

--> 1 - Valid Integer String


Enter an Integer String <999 to Exit> : 32

--> 32 - Valid Integer String


Enter an Integer String <999 to Exit> : 9876

--> 9876 - Valid Integer String


Enter an Integer String <999 to Exit> : 999

--> 999 - Valid Integer String


The first call, above, indicates that the Null string is not a valid integer string. In the second call, the user accidentally entered an 'l' instead of a '1'; this common typing error is correctly processed with our function. The number passed in the third call, 12312, is technically an integer, but in accordance with our specification, we reject all five digit integers. This is one of many ways that our IsIntStr function can be more robust; it shall be left as an exercise. The number passed in the fourth call, 12312, is also technically an integer, but in accordance with our specification, we reject all integers that begin with a plus or minus sign. This is another way that our IsIntStr function can be more robust; it too shall be left as an exercise. The last four calls reflect correct one, two, three and four digit integers.


Example 7.21

Imagine the problems trying to match character data in a database. Suppose the original name were entered "John DOe".




char

Name;
printf ("Enter Name : ");

gets (Name); Enter Name : John DOe

Searches for "John Doe" or "JOHN DOE" or "john doe" would all prove unsuccessful.




printf ("Enter Sought Name : "); Enter Sought Name : John Doe

gets (SoughtName); Enter Sought Name : john doe

if (strcmp(SoughtName, Name) == 0) Enter Sought Name : JOHN DOE


The user might have to try many combinations, before finding John. If we had a function, UpperCase, which would convert a string to all capital letters, it would be easier for the user to find matches.

printf ("Enter Name : ");

gets (Name); Enter Name : John DOe

UpperCase1 (Name);

printf ("Enter Sought Name : ");

gets (SoughtName); Enter Sought Name : John Doe

UpperCase1 (SoughtName);

printf ("%s - %s\n",Name, SoughtName); JOHN DOE - JOHN DOE

if (strcmp(SoughtName, Name) == 0)


Let us write a subprogram, called UpperCase, which will change all lowercase letters in a string to uppercase letters.
void UpperCase1 (char String[])

{

int



Pos;

for (Pos = 0; String[Pos]; Pos++)

{

if ((String[Pos] >= 'a') && (String[Pos] <= 'z'))



String[Pos] = String[Pos] - 32;

}

}


It is important to alter only the lowercase letters! If we test the function with


strcpy (TempString,"123ABCabc(*&^");

puts(TempString);

UpperCase1(TempString);

puts(TempString);




then the following output would be generated.


123ABCabc(*&^

123ABCABC(*&^



Example 7.22

Let us write a code fragment which will continue to prompt the teacher for an integer exam score, in the range 10 - 100, until the user enters a valid choice.

The valid integer range is {-32768, -32767, ... , +32766, +32767}. We have already discussed the importance of selecting data types of the proper size. The programmer has control and can avoid errors such as the one below.


int

No;
No = 32768;

printf ("No = %d\n",No); No = -32768

The programmer has little control when the user enters an invalid integer from keyboard in response to scanf.




int

No;
printf ("Enter No : ");

scanf ("%d",&No); Enter No : 32768

printf ("No = %d\n",No); No = -32768


The programmer has even less control when the user enters non digits from keyboard in response to scanf.




int

No;
printf ("Enter No : ");

scanf ("%d",&No); Enter No : 32a68

printf ("No = %d\n",No); No = 32 [a68 still in buffer]





The stdlib.h contains a function to convert a character string to a valid integer value; this function is called atoi. With the proper include file, the code fragment


No = atoi ("234");

printf ("[%d]\n", No);

printf ("[%d]\n", atoi ("32767"));

printf ("[%d]\n", atoi ("32768"));




would produce the output below.


[234]

[32767]


[32767]

Function atoi works correctly for valid integer strings. The last call above, atoi("32768"), is not processed correctly because "32768" is not a valid integer string.

Let us now return to the task at hand. Even though our IsIntStr1 is not as robust as we would like, we shall use it in our solution.


do

{

Exam = -999;



printf ("Enter an Exam Score [10-100] : ");

gets(ExamString);

if (IsIntStr1(ExamString))

{

Exam = atoi(ExamString);



if (Exam > 100)

printf ("--> [%d] - Too Big!\n\n",Exam);

else if (Exam < 10)

printf ("--> [%d] - Too Small!\n\n",Exam);

}

else


printf ("--> [%s] - Not a Valid Integer String\n\n",

ExamString);

}

while ((Exam > 100) || (Exam < 10));


Output from the code fragment above might be :




Enter an Exam Score [10-100] : 5

--> [5] - Too Small!


Enter an Exam Score [10-100] : 105

--> [105] - Too Big!


Enter an Exam Score [10-100] :

--> [] - Not a Valid Integer String


Enter an Exam Score [10-100] : 5a

--> [5a] - Not a Valid Integer String


Enter an Exam Score [10-100] : a5

--> [a5] - Not a Valid Integer String


Enter an Exam Score [10-100] : 1r1

--> [1r1] - Not a Valid Integer String


Enter an Exam Score [10-100] : 95

All user-friendly systems

(1) read potential numeric responses in string format (NoString)

(2) verify the correctness of the string (NoString)

(3) convert the string (NoString) to numeric format (No)

(4) verify the range of the response No <= HIGH and No >= Low

(5) provide appropriate error responses
Can you imagine the amount of code necessary to process each and every input (thousands) on a large interactive system? The computer scientist would quickly begin to wonder if it were not time to modify GetAnInteger1 to simplify the coding and reduce the redundancy. The prototype for GetAnInteger1 is
boolean GetAnInteger1 (char Prompt[], int *NewInt, int Low, int High, int Sentinel);
With a more robust IsIntString function, a much more user-friendly GetAnInteger2 can be designed. This is left as an exercise.

––––––––––––––––––––––



PROGRAMMING'>FOCUS ON

PROGRAMMING

––––––––––––––––––––––

The sample program for this chapter features the use of arrays and subprograms. Since sorting an array is a common practice, it has been included as part of the program. Specifically, suppose the Home Sales Realty Company, Inc. wants to print a list containing the amount of all sales for a month. Each sale amount is provided by the user and the number of homes sold is less than 20. Write a program to do the following:
1. Read the data from keyboard input.

2. Print the data in the order in which it is read with a suitable header and format.

3. Print a sorted list (high to low) of sales with a suitable header and format.

4. Print the total number of sales for the month, the total amount of sales, the average sale price, and the company commission (7 percent).


Sample input would be
65000

56234


95100

78200


101750

56700
where each line represents the sale price of a home. Typical output would include an unsorted list of sales, a sorted list of sales, and appropriate summary data.


A first–level pseudocode development is
1. FillListFromKeyboard

2. PrintList

3. SelectionSortList

4. PrintList

5. Compute

6. PrintResults


Notice that PrintList is called twice and PrintResults includes output for number of sales, total of sales, average sale price, and company commission. These are printed with suitable headings.

Figure 7.4

Hierarchy Structure

Chart for Home Sales

Reality Company


Module specifications for the main modules are


1. FillListFromKeyboard

Data received: None

Information returned: Sales for a Month

Actual Number of Sales

Logic: Use a while loop to read entries into an array.
2. DisplayList Module

Data received: Array of Sales

Actual Number of Sales

Information returned: None

Logic: Use print statements to display a suitable heading for an unsorted list.

Use a for loop with the array length as a loop control variable to print the list of sales for a month.


3. SelectionSort Module

Data received: Actual Number of Sales

Information returned: Sorted Array of Sales

Logic: Use a selection sort to sort the array.


4. Compute Module

Data received: Array of Sales

Actual Number of Sales

Information returned: Total Sales

Average Sale

Company Commission

Logic: Compute the total sales.

Compute the average sale.

Compute company commission by using a defined constant, CommissionRate.
5. PrintResults Module

Data received: Total sales

Average sales

Company commission

Information returned: None

Logic: Use print statements to display a summary report.


This program illustrates the use of Arrays with functions. Note the use of both value and variable parameters. Also note that a function is used to sort the Array.

PROGRAM

Reality.c
/*******************************************************************************

** Purpose: This program illustrates the use arrays with procedures. **

** It includes filling an array from keyboard, sorting the **

** array, and calculating the sum of its elements and its **

** average. **

** Modules Required: ClearScreen, PrintHeading, GetAFloat **

*******************************************************************************/
# include

# include


# define COMPANY_COMMISSION 0.07

# define MAX_SALES 20

# define True 1

# define False 0

# define SUCCESSFUL 1

# define UNSUCCESSFUL 0


typedef int boolean;
void FillListFromKeyboard (float List[], int *ActNo, int Max);

void DisplayList (char Title[], float List[], int ActNo);

void SelectionSort (float List[], int ActNo);

void Compute (float List[], int ActNo, float *Sum, float *Average,

float *Commission );

void PrintResults (float TotalSales, float AverageSale,

float CompanyCommission );

boolean GetFloat1 (char Prompt[], float * Newfloat, float Low, float High,

float Sentinel);
main ()

{

int



ActNoSales=0;

float


Sales [ MAX_SALES + 1],

TotalSales, AverageSale, CompanyCommission;


FillListFromKeyboard (Sales, &ActNoSales, MAX_SALES);

DisplayList (" Unsorted Sales For June",Sales, ActNoSales);

SelectionSort (Sales, ActNoSales);

DisplayList (" Sorted Sales For June",Sales, ActNoSales);

Compute (Sales, ActNoSales, &TotalSales, &AverageSale, &CompanyCommission);

PrintResults (TotalSales, AverageSale, CompanyCommission);

}
/*******************************************************************************

** Purpose: Fill a float array from keyboard and update the ActNo counter. **

** Use Elements 1..Max **

** Modules Required: None **

** Headers Required: stdio.h **

** Globals Required: None **

** Defines Required: None **

*******************************************************************************/

void FillListFromKeyboard (float List[], int *ActNo, int Max)

{

boolean



Done = False;

char


Prompt[30];
*ActNo = 0;

do

{ /* sprintf - print to string - fills Prompt with Enter List [1] */



sprintf (Prompt,"Enter List [%d]",(*ActNo)+1);

if (GetFloat1 (Prompt, &List[(*ActNo)+1], 0, 500000, -1) )

(*ActNo)++;

else


Done = True;

}

while ((*ActNo < Max) && (!Done));



}
/*******************************************************************************

** Purpose: Display a title line and the contents of a float array. **

** Modules Required: None **

** Headers Required: stdio.h **

** Globals Required: None **

** Defines Required: None **

*******************************************************************************/

void DisplayList (char Title[], float List[], int ActNo)

{

int


Counter;

printf ("\n\n%s\n\n", Title);

for (Counter = 1; Counter <= ActNo; Counter++ )

printf (" <%2i> $%8.2f\n", Counter, List[Counter]);

}
/*******************************************************************************

** Purpose: Selection Sort a float array in ascending order **

** Modules Required: None **

** Headers Required: stdio.h **

** Globals Required: None **

** Defines Required: None **

*******************************************************************************/

void SelectionSort (float List[], int ActNo)

{

int


IndexSmallestNo,

Pass,


Subscript;

float


TempFloat;

for (Pass = 1; Pass <= ActNo-1; Pass++ )

{

IndexSmallestNo = Pass;



for (Subscript = Pass + 1;Subscript <= ActNo;Subscript++)

if (List[Subscript] < List[IndexSmallestNo])

IndexSmallestNo = Subscript;

TempFloat = List[IndexSmallestNo];

List[IndexSmallestNo] = List[Pass];

List[Pass] = TempFloat;

}

}
/*******************************************************************************



** Purpose: Compute the sum, average, and commission for a float array. **

** Modules Required: None **

** Headers Required: stdio.h **

** Globals Required: None **

** Defines Required: COMPANY_COMMISSION **

*******************************************************************************/

void Compute (float List[], int ActNo, float *Sum, float *Average,

float *Commission )

{

int


Index;

(*Sum) = 0;

for (Index = 1; Index <= ActNo; Index++)

(*Sum) = (*Sum) + List[Index];

(*Average) = (*Sum)/ActNo;

(*Commission) = (*Sum) * COMPANY_COMMISSION;

}
/*******************************************************************************

** Purpose: Print the Total Sales, Average Sale, and Company Commission **

** Modules Required: None **

** Headers Required: stdio.h **

** Globals Required: None **

** Defines Required: None **

*******************************************************************************/

void PrintResults (float TotalSales, float AverageSale,

float CompanyCommission )

{

printf ("\n\n Statistics\n ----------\n\n");



printf (" Total Sales = $%10.2f\n\n", TotalSales);

printf (" Average Sale = $%10.2f\n\n", AverageSale);

printf (" Company Commission = $%10.2f\n\n", CompanyCommission);

}

The output from Reality.c is as follows:






Enter List [1] < -1.000000 to Exit> : 65000

Enter List [2] < -1.000000 to Exit> : 56234

Enter List [3] < -1.000000 to Exit> : 95100

Enter List [4] < -1.000000 to Exit> : 78200

Enter List [5] < -1.000000 to Exit> : 101750

Enter List [6] < -1.000000 to Exit> : 56700

Enter List [7] < -1.000000 to Exit> : -1

Unsorted Sales For June


< 1> $65000.00

< 2> $56234.00

< 3> $95100.00

< 4> $78200.00

< 5> $101750.00

< 6> $56700.00

Sorted Sales For June


< 1> $56234.00

< 2> $56700.00

< 3> $65000.00

< 4> $78200.00

< 5> $95100.00

< 6> $101750.00

Statistics

----------
Total Sales = $ 452984.00
Average Sale = $ 75497.34
Company Commission = $ 31708.88

––––––––––––––––––––––



Download 0.51 Mb.

Share with your friends:
1   2   3   4   5   6




The database is protected by copyright ©ininet.org 2024
send message

    Main page