I am making simple encrypt/decrypt program in Lazarus with 2 buttons, one for encrypt and one for decrypt. I also have two memo boxes (or just two memos ).
I tested my algorithm and it works but when i tried implementing it in user friendly app i got this problem.
I have this function:
function enc(x:string):string;
var
y:string;
p,q:integer;
m:char;
begin
y:=x[1];
for p:=2 to Length(x)do
begin
q:=p-1;
if chr(ord(x[p]))=' ' then
m:='!'
else if ord(x[p])>ord(x[q]) then
m:=Succ(chr(ord(x[p])))
else
m:=Pred(chr(ord(x[p])));
Y:=y+m ;
end;
enc:=y;
end;
and one procedure to call this function
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Text:=enc(Memo2.Text);
end;
I compiled program and it worked but when i tried to enter some text and encrypt that text i got this error
exception class 'External: SIGSEGV'
In file 'unit1.pas' at line 46: y:=x[1];
I recently started to learn pascal and to use lazarus soo sry if this Q is stupid but i really want to know what I'm doing wrong.
That error, for that code, implies that x is an empty string. If the first character is not valid, then what else could x be, other than empty?
Related
It has been around 20 years since I last had to write in Pascal. I can't seem to use the structure elements of the language correctly where I am nesting if then blocks using begin and end. For example this gets me an Compiler Error "Identifier Expected".
procedure InitializeWizard;
begin
Log('Initialize Wizard');
if IsAdminLoggedOn then begin
SetupUserGroup();
SomeOtherProcedure();
else begin (*Identifier Expected*)
Log('User is not an administrator.');
msgbox('The current user is not administrator.', mbInformation, MB_OK);
end
end;
end;
Of course if I remove the if then block and the begin end blocks associated with them then everything is OK.
Sometimes I get it this kind of syntax right and it works out OK, but the problems become exasperated when nesting the if then else blocks.
Solving the problem is not enough here. I want to have a better understanding how to use these blocks. I am clearly missing a concept. Something from C++ or C# is probably creeping in from another part of my mind and messing up my understanding. I have read a few articles about it, and well I think I understand it and then I don't.
You have to match every begin with an end at the same level, like
if Condition then
begin
DoSomething;
end
else
begin
DoADifferentThing;
end;
You can shorten the number of lines used without affecting the placement, if you prefer. (The above might be easier when you're first getting used to the syntax, though.)
if Condition then begin
DoSomething
end else begin
DoADifferentThing;
end;
If you're executing a single statement, the begin..end are optional. Note that the first condition does not contain a terminating ;, as you're not yet ending the statement:
if Condition then
DoSomething
else
DoADifferentThing;
The semicolon is optional at the last statement in a block (although I typically include it even when it's optional, to avoid future issues when you add a line and forget to update the preceding line at the same time).
if Condition then
begin
DoSomething; // Semicolon required here
DoSomethingElse; // Semicolon optional here
end; // Semicolon required here unless the
// next line is another 'end'.
You can combine single and multiple statement blocks as well:
if Condition then
begin
DoSomething;
DoSomethingElse;
end
else
DoADifferentThing;
if Condition then
DoSomething
else
begin
DoADifferentThing;
DoAnotherDifferentThing;
end;
The correct use for your code would be:
procedure InitializeWizard;
begin
Log('Initialize Wizard');
if IsAdminLoggedOn then
begin
SetupUserGroup();
SomeOtherProcedure();
end
else
begin
Log('User is not an administrator.');
msgbox('The current user is not administrator.', mbInformation, MB_OK);
end;
end;
I'm looking for an easy/quick way to identify and extract hashtags from a string, and temporarily store them separately - e.g.:
If I have the following string:
2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure).
Then I want to be able to get this:
#Example
#Date:2017-09-01
#NothingWow
I figured storing it in a TStringList should be sufficient until I'm done. I just need to store them outside of the original string for easier cross referencing, then if the original string changes, add them back at the end.
(but that's easy - its the extracting part I'm having trouble with)
It should start at the # and end/break when it encounters a [space].
The way I initially planned it was to use Boolean flags (defaulted to False), then check for the different hashtags, set them to true if found, and extract anything after a [:] separately.
(but I'm sure there is a better way of doing it)
Any advice will be greatly appreciated.
The following shows a simple console application which you could use as the basis
for a solution. It works because assigning your input string to the DelimitedText property of a StringList causes the StringList to parse the input into a series of space-limited lines. It is then a simple matter to look for the ones which start with a #.
The code is written as a Delphi console application but should be trivial to convert to Lazarus/FPC.
Code:
program HashTags;
{$APPTYPE CONSOLE}
uses
Classes, SysUtils;
procedure TestHashTags;
var
TL : TStringList;
S : String;
i : Integer;
begin
TL := TStringList.Create;
try
S := '2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure)';
TL.DelimitedText := S;
for i := 0 to TL.Count - 1 do begin
if Pos('#', TL[i]) = 1 then
writeln(i, ' ', TL[i]);
end;
finally
TL.Free;
end;
readln;
end;
begin
TestHashTags;
end.
PROGRAM approvedapplicants(input,output);
uses crt;
var
applcntname,housingcomm,clarendon_court,providence_gardens,
sangre_grande_villas:string;
slry,spcslry:integer;
c_qual_sal,s_qual_sal,p_qual_sal,qualifying_salary:integer;
BEGIN
writeln('enter applicant name, salary, spouce salary');
readln(applcntname,slry,spcslry);
writeln('enter housing community');
readln(housingcomm);
BEGIN
qualifying_salary:=0;
IF(housingcomm=clarendon_court)
then
qualifying_salary:=$12500;
writeln('you have selected clarendon court!');
readln(c_qual_sal) ;
end if ;
else if(housingcomm=sangre_grande_villas)then
qualifying_salary:=$9500;
writeln('you have selected sangre grande villas!');
readln(s_qual_sal);
end if ;
else(housingcomm=providence_gardens)then;
qualifying_salary:=$7500;
writeln('you have selected providence gardens!');
readln(p_qual_sal);
end if;
END.
Ordinarily, on SO, we don't post answers to homework/coursework, but your code is so far wide of the mark that I think it's ok to make an exception in this case.
Try compiling and running this program, which I think does pretty much what I think you are intending, then I'll explain a few things about it:
program approvedapplicants(input,output);
uses crt;
var
ApplicantName,
HousingCommunity,
ClarendonCourt,
ProvidenceGardens,
SangreGrandVillas :string;
Salary,
SpouseSalary,
QualifyingSalary : Integer;
CQualSal,
PQualSal,
SQualSal : Integer;
slry,spcslry:integer;
begin
ClarendonCourt := 'Clarendon Court';
ProvidenceGardens := 'Providence Gardens';
SangreGrandVillas := 'Sangre Grand Villas';
QualifyingSalary := 0;
writeln('enter applicant name');
readln(ApplicantName);
writeln('enter salary');
readln(Salary);
writeln('enter spouse salary');
readln(SpouseSalary);
writeln('enter housing community');
readln(HousingCommunity);
if (HousingCommunity = ClarendonCourt) then begin
QualifyingSalary := $12500;
writeln('you have selected clarendon court!');
readln(CQualSal);
end
else
if(HousingCommunity = SangreGrandVillas)then begin
QualifyingSalary := $9500;
writeln('you have selected sangre grande villas!');
readln(SQualSal);
end
else
if HousingCommunity = ProvidenceGardens then begin
QualifyingSalary :=$7500;
writeln('you have selected providence gardens!');
readln(CQualSal);
end;
end.
Firstly, notice how much easier it is to read and follow its logic. This is mainly
because of
The use of a layout (including indented blocks) which reflects the logical
structure of the code.
The use of consistent, lower case for keywords like program, begin, end, etc.
Keywords are usually the least interesting contents of source code, and it is distracting
to have them SHOUTing at you.
The avoidance of arbitrarily dropping characters from variable names (like the "i"
and second "a" of "applicant". In the days of interpreted code running on slow machines there was
argubably some justification for this, but not any more imo. Likewise, the avoidance
of underscores in variable names - admittedly this is more of a personal preference, but
why have you used them everywhere except the applicant's name?
Secondly, you still have quite a bit of work to do.
Having 3 different variables for the salary (?) numbers you prompt the user
for, one for each of the 3 communities, is probably a bad idea unless you will
subsequently want to work with all 3 figures at the same time. Also, you haven't provided text prompts to tell the user what information to enter for the readln(c_qual_sal) etc statements. It wasn't obvious to me what you intend, so I have not tried to guess.
The way you echo the user's choice of community is just creating you a maintenance
headache (what if you want to add more communities later?). It would be better
to have a variable which you set to whichever of the community names matches
what the user has entered.
You have 3 statements to execute for each community, which are duplicated for
each community. The only one you actually need is the QualifyingSalary one -
the others can execute regardless of the inputted community.
So I just worked on a generic program for school which uses the sort algorithms. The teacher always loves putting everything into different units so I decided to create an "output" procedure which gives an output of the sorted array.
unit selectionsort;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, typen, ausgabe;
procedure SSort (FeldS: t_Feld);
implementation
procedure SSort (FeldS: t_Feld);
var h,j,min,hilf: integer;
begin
for h:= 1 to c-1 do
begin
## all the sorting stuff
end;
**ausgabe(FeldS);**
end;
end.
(ausgabe is german for output)
unit ausgabe;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, typen;
procedure ausgabe(FeldA: t_feld);
implementation
procedure ausgabe(FeldA: t_feld);
begin
for i:= 1 to c do
begin
write(FeldA[i], ' ');
end;
readln();
end;
end.
The bold part (when calling the procedure ausgabe) is where I get the error: fatal: Syntax error, "." expected but "(" found. I know I could just delete the procedure "Ausgabe" and do the output in the sort procedures but I would like to do it this way.
As the procedure ausgabe and the unit have the same name (this is possible as they are in different scopes), the compiler assume a so-called "qualified identifier": unitname.procedurename. This is needed if multiple units have identifiers with the same name. To overcome the error: Either you rename the unit or the procedure or you call the procedure using its qualified name (the first ausgabe is the name of the unit where the compiler should search for the symbol, the second ausgabe is the actual procedure name):
ausgabe.ausgabe(FeldS);
This snippet not only causes a runtime error, it makes FPC close if I run it using the debugger.
procedure sortplayersbyscore(var vAux:tplayers);
procedure swap(var a:trplayers;var b:trplayers);
var
rAux:trplayers;
begin
rAux:=a;
a:=b;
b:=rAux;
end;
var
i,j:integer;
sorted:boolean;
begin
vAux:=playersarray;
i:=1;
sorted:=false;
while (i <= MAXPLAYERS -1) and not sorted do
begin
j:=1;
sorted:=true;
while (j <= MAXPLAYERS -i) do
begin
if (vAux[j].score < vAux[j+1].score) then
begin
swap(vAux[j],vAux[j+1]);
sorted:=false;
end;
inc(j);
end;
inc(i);
end;
end;
The code itself is part of a really big source file, I can post the whole thing but the responsible for the error is just that bunch of lines. The debugger terminates at line:
swap(vAux[j],vAux[j+1]);
tplayers is just a type defined as an array of records that contain score (an integer) among a bunch of other variables. trplayers is the type of the aforementioned records. I'm at a total loss; FPC (while not under debugging mode) spits an out-of-range error but under my watches I see that the variables I'm trying to read exist. Any help is really appreciated!
rAux:trplayers; have you typed a wrong symbol or the type here really contains "r" in its name?
It looks valid (other than typos) ... so let's try something simple.
What's the value of "j" when you abort?
If the debugger won't tell you, try adding:
writeln ('j = ', j);
just before the "swap" call.
As Yochai's question implied, your array needs to be dimensioned at least from
1 (or lower) to MAXPLAYERS (or larger). (I.e.: 0..MAXPLAYERS-1 would not work,
but 1..MAXPLAYERS should.)