Duoas 1,025 Postaholic Featured Poster

Thanks. Please keep in mind that the OP (and most other readers here) haven't read (nor will they) the R5RS.

The R5RS committee needed a word for a technical thing. They chose poorly (though, considering the circumstances and the technical issues, I don't blame them).

A "procedure" is a very broad term. In most computing contexts that I am aware of, procedures return value by way of side-effect only, whereas functions explicitly return value.

In Scheme, a combination (a lambda), is a function call: local values are bound to an expression which is evaluated for value. That value then replaces the local context. Please keep in mind that this is a functional operation --hence the term functional languages.

Please understand that I'm not being rude. You are very correct. However, you must be careful not to confuse those reading here with those who care about all the technicalities and terminologies specific to functional languages and Scheme in particular.

To be short: in Scheme it is meaningless to talk about the difference between a procedure and a function. But in the minds of programmers everywhere, unfamiliar with Scheme, the difference is in "how do I then get this value to be passed out of the procedure". The answer is, there are no procedures in scheme (or any other functional language). Only functions (or lambdas) that evaluate to (or "return") a new value. You pass a value out by evaluating to that value.

I hope I've …

Duoas 1,025 Postaholic Featured Poster

Actually, it is the preprocessor: cpp. Modern preprocessors are a lot smarter than they used to be. They actually tokenize the input. By using the "traditional" cpp mode, where the strings are simply replaced by new text in the input stream, the code is transformed properly for this program. Remember: -_ becomes: --F<00||--F-OO--; Without that minus sign out in front of the underscore, the first condition is just: -F<00 , which is incorrect.

I use MinGW happily. If you go to their site on sourceforge, you'll get a huge list of weird file names, like: gcc-ada-3.4.2-20040916-1.tar.gz. The first part (gcc-ada) is the package name. The second part is the version number (3.4.2). The third part is the date the package was compiled. The last part (1) is the package type. And finally, of course, the file extension.

You'll need/want the following packages:
gcc-core
gcc-g++
mingw-runtime
mingw-utils
binutils
mingw32-make
w32api

Look for stuff in the "current" section first. Otherwise try to get the latest version. You want the package type to be "bin". It will either say "bin" or nothing. Don't get "src" or anything else... Download them all to C:\MinGW\. Unpack them. Some come as exe. Some as zip. Some as tar.gz. Once unpacked you can delete the files you downloaded. Add C:\MinGW\bin to your path, and you're good to go.

(Personally, I prefer to keep it in C:\PROGRA~1\MinGW, it works fine. However, some utilities can't handle spaces in …

Duoas 1,025 Postaholic Featured Poster

I get the following output: -201 -16 3.141 Did you compile with gcc -traditional-cpp ?


The printf statement just uses as few characters as needed to work. 4. floating point number * -F since F is negative, make it positive. (4.0 * (-F)) is a float. /OO float division (since numerator is float) /OO float division


Enjoy.

Jishnu commented: You've helped me a lot :) +2
Duoas 1,025 Postaholic Featured Poster

Ah.

It's just a giant math expression.

If you want to see it in action why don't you write something that traces the values of the variables F and OO?

If you do, you'll see that it uses a cheap trick based upon the circular shape of the _-_ sequences.

Each line of the circle separates an expression.
Each _ becomes (essentially) F--; OO--; and each -_ that follows it on the line becomes F--; That's the first cheap trick. The second cheap trick is where the lines separate. You'll notice that the lines separate around the circumference of the circle. The physical shape of the program affects the calculation --that is, F is modified each statement, but OO is only modified once per line. The amazing crazyness is that the circular shape is itself an approximation of PI. If you were to change it to a square or any other shape it wouldn't work. You can add more _-_'s to get a more accurate approximation, but the shape must remain a circle. (In other words, as you increase the resolution of the graph, you increase the accuracy of the computation.)

More than this you'll have to think about it yourself. Good luck.

Duoas 1,025 Postaholic Featured Poster

It's just a giant math expression.

Why are you trying to learn programming by looking at programs that are specifically designed to be hard to understand?

Duoas 1,025 Postaholic Featured Poster

That program computes an approximation of PI by computing its own area. If you want to get more digits out of it, write a bigger program. [ 1 ]

BTW. That one's been around for years. It's one of the oldest entries in the International Obfuscated C Code Contest .

Duoas 1,025 Postaholic Featured Poster

Argh. Missed a key:

[EDIT] As an addendum, you should note that "is_it_even" works fine. That's because the scope inside the "is_it_even" function is inside that "oddstuff" unit. So is_it_even calls the correct is_it_odd function. [/EDIT]

Duoas 1,025 Postaholic Featured Poster

Oy, after all that typing you beat me to the punch with another Q.

Second tutorial: scope.

Just as the functions and procedures above all belonged to tMatrix, so do the variables. Remember how you can do something like:

program McGonagalls_notes;
type
  tStudent = record
    name: string;
    grade: integer
    end;

var
  my_student: tStudent;

begin
  with my_student do
    begin
    name := 'Hermione Granger';
    grade := 100
    end
end.

Professor McGonagall remembered that when she is only thinking of one particular student, she doesn't need to remember all the information about where or how the student is referenced --she can just concentrate on that particular student. If she had preferred, she could have just said:

my_student.name := 'Hermione Granger';
my_student.grade := 100;

It is the exact same thing, but written using different scoping rules (by using the with statement).

The scope is what you can see at the moment. In an earlier example I created a unit to return whether a number is odd or even. Now, consider the following:

program oddness;
uses oddstuff;

procedure is_it_odd( n: integer ): boolean;
  begin
  result := FALSE;
  end;

var x: integer;

begin
  write( 'Please enter a whole number greater than zero> ' );
  readln( x );
  writeln( 'The statement "', x, ' is odd" is ', is_it_odd( x ), '.' );
  writeln( 'The statement "', x, ' is even" is ', is_it_even( x ), '.' )
end.

Now, the question is, "Which is_it_odd function gets called? The one in the unit or …

squidd commented: very well written and helpful +1
Duoas 1,025 Postaholic Featured Poster

Ah.

The difference is whether the function is a method of the TMainForm class or not.

A quick tutorial:

Forward declarations vs. automatic declarations

Normally you might have a program that looks like this:

program foo;

function triple_it( x: real ): real;
  begin
  triple_it := x *3
  end;

var
  number: real;

begin
  write( 'Please enter a number to be tripled> ' );
  readln( r );
  writeln( r, ' tripled is ', triple_it( r ) )
end.

In this little program, we have both declared and defined a function named "triple_it". By declaring, we mean that we have told the compiler that it exists. By defining, we mean that we have told the compiler all the details about it. Typically, as in this example, things are declared at the same time they are defined. That is, by defining a thing we implicitly declare it as well.

In Pascal, a thing must be at least declared before it is used.

Sometimes, however, we need to tell a program that something exists before we actually define it. Hence, we need to use a forward declaration. Here's a simplistic example lifted off of the Wikipedia (and repaired for correctness):

program oddness;

function is_it_even( n: integer ): boolean; forward;

function is_it_odd( n: integer ): boolean;
  begin
  if n = 1
    then is_it_odd := TRUE
    else is_it_odd := is_it_even( n -1 )
  end;

function is_it_even;
  begin
  if n = 1
    then is_it_even := FALSE
    else is_it_even := is_it_odd( n -1 ) …
Duoas 1,025 Postaholic Featured Poster

What you have written looks right. But just to make sure you got there correctly (which makes all the difference):

1. You added a button to your form and named it "ReverseOrderButton".
2. You either a) double-clicked the button on your form, or b) changed the object inspector to list events and double clicked the "OnClick" item
3. You added your code.

Yes, it does something. However, in the example posted you reverse an uninitialized local string. That is, a string that only exists in the ReverseOrderButtonClick function and which you did not s := "hello"; before reversing, and which you have not displayed before the procedure quits and the string disappears. So, while you have reversed the string '', it never gets displayed and it appears that nothing happens.

Try this to see what it does:

procedure TMainForm.ReverseOrderButtonClick( Sender: TObject );
  begin
  with ReverseOrderButton do
    Caption := StringReverse( Caption )
  end;

The same is true for any Item[ x ].Caption .

Hope this helps.

Duoas 1,025 Postaholic Featured Poster
Duoas 1,025 Postaholic Featured Poster

Just as a random addendum. Above I said you could make your ADT as: (define (rank card) (car card)) That's fine, but if you really want to wow, forget the fluff and just say: (define rank car) Heh heh heh...

Duoas 1,025 Postaholic Featured Poster

Yeah, I just found it when reading here. I never knew you could do that before.

IMO, there is no reason to put labels on buttons except to get different fonts or font styles on a single button. My $0.02.

Duoas 1,025 Postaholic Featured Poster

Just caught this...

Your documentation must be damaged. There is no error in what I have.
Where did you get your HLP files?

Like I said, mine are a bit old, but I can send it to you if you like.

Duoas 1,025 Postaholic Featured Poster

A TButton was not designed as a container component, so the IDE won't let you put labels in buttons. Why not just change the button's caption?

If you must, however, see this thread.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Windows was designed as a 'do everything' GUI, so you automatically get things like GetFontMetrics().

X11 is an entirely different beast. I don't know of any standard libraries for stuff you want. If you are willing to use QT then I highly recommend it. It is a powerful system for this kind of stuff. I recommend you to the QT Online Reference Documentation. It is very complete and is chuck-full of examples.

Otherwise you are going to have to go pretty low-level.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

The ButtonClick event procedures only get called if the user clicks the button. So nothing will grey if the 'set disabled' code is in the button click procedure. The place to grey the button is in the load procedure: after loading the file, check to see how many items there are. If more than 10,000, then disable the appropriate buttons...

In Windows applications, things only occur when the user clicks something, or types something, or etc. The only exceptions are system events (which you don't need to worry about) and timer events (if you drop a TTimer on your form).

To set the application icon, go to project options --> Application. There should be a spot to set the program icon and the program title.

Duoas 1,025 Postaholic Featured Poster

Of course. You'll need to read up on recursion.

There is a basic principle: if you have a list (a b c d) (which, if you remember, is really: (a . (b . (c . (d . ())))) and if you can do something to the car of the list (or a ) and the cdr of the list (that is, the rest of the list: (b c d) ),
then you can do something to the whole list.

Remember, your list is a list of 'card's. So you'll have to use the card ADT to get the rank of each card and compare its value.

Hope this gets you started. Using scheme (and other functional languages) require you to think pretty hard.

Duoas 1,025 Postaholic Featured Poster

You are on the right track. The only problem is that char is a single character, not a whole list of them (or array of them). You probably want to use a pointer to an array of chars.

Also, don't use %s in scanf() without qualifying it with a maximum width.

char *getString(char *string);

int main() {
    char string[200];
    getString(string);
}

char *getString(char *string) {
    scanf("%200s",string);
    return string;
}

You can pass the length of the target string into the function if you want:

char *getString( char *string, int length ) {
  char format[ 30 ];
  sprintf( format, "%%%ds", length );
  scanf( format, string );
  return string;
  }

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Since a "hand" object is a list of cards, and you want to get a list of cards from a hand, all you need to do is return the hand: (define (contents hand) hand) Now, if a "hand" object were something else, you'd need to do some work to turn it into a list...

Just wondering though, how can i seperate the two things in a card in a hand? would it be (suit (car hand)) etc?

Exactly. :)

Duoas 1,025 Postaholic Featured Poster

Sorry, I should have made myself more clear.

Try this:

procedure TMainForm.RemoveDuplicatesButtonClick(Sender: TObject); 
  var
    i, j, num_removed: integer;
  begin
    num_removed := 0;
    for i := 0 to ListView1.Items.Count - 1 do
      for j := ListView1.Items.Count-1 downto i+1 do
        begin
        if i = j then continue;  // <-- this line shouldn't be necessary
        if ListView1.Items[i].Caption = ListView1.Items[j].Caption then
          begin
          ListView1.Items.Delete(j);
          inc( num_removed )
          end;
        Application.ProcessMessages;
        end;
    ListView1.Columns[0].Caption := inttostr(ListView1.items.Count);
    CurrentStatusLabel.caption := 'Removed ' + inttostr(num_removed) + ' Duplicates';
  end;

I didn't actually test this code --it's late and I'm going to bed now... Also, with the revised j loop I don't think you need to test for i = j, it should never happen. (Alas, my brain is shot right now...)

Good luck.

squidd commented: Always an enormous help to me and has never given up in his efforts to help me. No amount of thanks descirbes my appreciation for this individual! +1
Duoas 1,025 Postaholic Featured Poster

The TListView is going to be really slow no matter what. However, there are a couple of things you can do to help.

In your loop on line 9, you are starting at zero again. You don't need to check things already known not to be duplicates. Say instead: for j := i+1 to ListView1.Items.Count-1 do In the same vein, when you goto recheck you are starting all over. Since the items are ordered, you might want to work backwards: for j := ListView1.Items.Count-1 downto i+1 do When a duplicate is found and removed, you just continue on your merry way and ignore all the stuff you have already checked (and possibly removed).

You might want to consider using the ListView1.FindCaption method instead of the doing the inner loop yourself. That way you can just loop until FindCaption returns nil. I think that would probably add a time savings since the class can usually access its members faster than you can using the classes property accessors.

You can count how many you removed by incrementing a counter whenever you actually remove a duplicate and at no time else. Set the counter to zero before you do anything else. I'm sure you had something very close to this when you tried before.

Good luck.

Duoas 1,025 Postaholic Featured Poster

For code blocks. It is watermarked behind the text edit you get when posting.

Windows was written in C. Its API is in C. Every bit of your code is C. Most C++ compilers have windows header files (like <windows.h>) set up so that they can be use by both C and C++ programs, so even if you are compiling with C++ you are still only using C.
Since you have not used any C++ at all, I assumed that you were using C.

I know what the hell WinHelp is. I use it every day. I also have just about every piece of documentation about windows and the Win32 API. I suspect I have a fair deal better idea what is in there than you do. Further, I'm no C++ weenie. If you want help, you might want to consider that the people responding might know something about how to use the language.
If you had followed my instructions your compiler wouldn't have complained about &bmi. You have created a pointer to something, but that something does not exist. Until you create it, it never will. For what you want to do, you do not need to use a pointer.

The CreateDIBSection() function only allocates memory for the pixel data. It will not allocate your BITMAPINFO structure. Rather, it expects you to have one already, which it uses to properly allocate your pixel data.

Finally, I know something about C/C++ compiler …

Duoas 1,025 Postaholic Featured Poster

Yes. A card is a single object. If you want a list of cards, then store a list of cards, not a list of suits and ranks.

(define dead-mans-hand (list
  (make-card 13 'spades)
  (make-card 13 'clubs)
  (make-card 8 'spades)
  (make-card 8 'clubs)
  (make-card 2 'hearts)
  ))

Thereafter, you can get, say, the second card's suit with: (suit (second dead-mans-hand)) Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Please, please, use [[I][/I]code[I][/I]] blocks to post. Anything else leaves unreadable and difficult to cut/paste stuff. Also, this is the C++ forum, not C.

You misunderstand a few basic concepts.

1
Anything with const in front of it cannot be modified. You don't need it here, especially since you intend to modify the value (after all, you want to create a bitmap you can edit in memory, right?).

2
Anything that looks like foo *bar; creates a pointer to something. That something doesn't exist until you use malloc() to create it. In this case, you don't need it to be a pointer. Just say:

BITMAPINFO bmi;

Since the BITMAPINFO structure contains a BITMAPINFOHEADER, there is absolutely no need to create another.

3
Anything that looks like foo bar = baz; is a variable declaration and a variable assignment combined into one. That is, it is equivalent to the two statments: foo bar; (Create a variable named "bar" of type "foo") bar = baz; (Assign the value "baz" to the variable "bar")
You need to say:

bmi.bmiHeader.biSize  = sizeof( BITMAPINFOHEADER );
bmi.bmiHeader.biWidth = 340;
...

This begins assigning values to the various fields inside the BITMAPINFOHEADER struct of the BITMAPINFO variable.

4
CreateDIBSection() does not create a file. It creates a bitmap (in memory). If you want to write the bitmap to file, I recommend you to this article I googled.

5
Watch the types of …

Duoas 1,025 Postaholic Featured Poster

>The program actually compiles if I use " instead of '. It actually doesn't compile if I use ' instead.
Sorry to address this first, but whaaat???? What compiler are you using? If it doesn't take ' but does take " then there is something seriously wrong. ' is Pascal. " is not. Never has been. Never will be.


OK, on to your real problem. :-/

Your loop is predicated upon something that never changes in the loop: legalinteger. The order you do things is also a little disorganized. Presumably you know that c is a digit when you first call convert. However, once you start the procedure, you read another c from the file and assume that it also is a digit. Don't. All your reads should be inside the loop.
Your loop should also be carefully structured so that you do not multiply digit1 by ten unless you already know that the next c is a digit.


Also, I think your professor is a crazy loon. So that's why you are using so many global variables and non-separable procedures. Would he concede to let you pass by reference? procedure fooey( var i: integer ); What you are doing is learning to program badly. There is no better way to say it. If this is really what your professor wants I think he should be fired.

[EDIT] Caught your last post. The edit button disappears once you log out.

Duoas 1,025 Postaholic Featured Poster

There are no procedures in scheme, only functions. Whenever you say define, you are naming an expression that evaluates to something.

Hence, follow along: (a-card 13 'spades) becomes (make-card 13 'spades) becomes (list 13 'spades) becomes '(13 'spades) The make-card and a-card functions do the same thing: take a rank and suit and return a card. Why not get rid of one of them?

I think you need to re-read your class notes about the difference between a list and a pair.

Personally, I would store the card as a pair: (define make-card (lambda (rank suit) (cons rank suit))) Or, using the shortcut syntax: (define (make-card rank suit) (cons rank suit)) Now, you know that a card is a pair of '(rank . suit), so to get out the rank or suit you only need a new function get knows what a card looks like: (define (rank card) (car card)) (define (suit card) (cdr card)) The purpose is to make it so that no one knows that a card is just a pair (or a list or something else). You know, because that is how you are storing it. But anyone else using your program only needs to know three functions: make-card rank suit : return a card object rank card : return the rank of a card object suit card : return the suit of a card object

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Any time you can group objects together into a single 'class' of thing you can use polymorphism. The concept behind COM objects are an example. Objects in a video game. Elements in a Raytracer (mesh, camera, curve, etc., materials, etc.). You can come up with all kinds of examples on your own.

Duoas 1,025 Postaholic Featured Poster

The overhead isn't so great as everybody goes on and on about. However, you should only make virtual those functions which need to be virtual. Typically only public and some protected methods are virtual, while private and some protected methods are static.

Duoas 1,025 Postaholic Featured Poster

An overloaded function is a function that shares its name with one or more other functions, but which has a different parameter list. The compiler chooses which function is desired based upon the arguments used.

An overridden function is a method in a descendant class that has a different definition than a virtual function in an ancestor class. The compiler chooses which function is desired based upon the type of the object being used to call the function.

A redefined function is a method in a descendant class that has a different definition than a non-virtual function in an ancestor class. Don't do this. Since the method is not virtual, the compiler chooses which function to call based upon the static type of the object reference rather than the actual type of the object.

For example, if you have an Animal *george , and george = new Monkey; , where Monkey inherits from Animal, if you say george->dosomething() the Animal.dosomething() method is called, even though george is a Monkey (even if a Monkey.dosomething() method is available).

Good luck.

Duki commented: Well said. Really helped me to put concepts into words. Thanks! +4
Duoas 1,025 Postaholic Featured Poster

I'm sorry. I goofed twice. It should read: cin.ignore( 10000, '\n' ); That'll fix it.

Duoas 1,025 Postaholic Featured Poster

Oop! You're right. The first doesn't throw an exception...

He'd have to test the first the same way: if (!(cin >> rating[ i ])) fooey(); The second only throws an exception because I threw it after testing the stringstream for the error state the same way...

Duoas 1,025 Postaholic Featured Poster

What he means is don't use cin >> myvar; alongside cin.get( mystring ); The problem comes because doing so breaks the user's input model. When you ask for something, the user types an answer and presses ENTER. The get() method returns the string entered and tosses the ENTER away. The >> method only gets the first thing the user typed and doesn't toss anything away.

You can fix the problem one of two ways:

// fix #1
cin >> rating[ i ];  // try to read an integer
cin.ignore( 10000 );  // ignore everything else and toss the ENTER
// fix #2
#include <sstream>
#include <exception>
...
string s;
...
cin.get( s );  // read everything
if (!(stringstream( s ) >> rating[ i ]))  // then convert to an integer
  throw runtime_error( "Not an integer!" );  // complain if not an integer

Both methods throw an exception if you try to enter something other than an integer. The second method is a tad easier to look at if you want to deal with the error...

Duoas 1,025 Postaholic Featured Poster

OK, I've had some time now. Yes, your problem is (mostly) in convert2.

First, a syntax error you should have caught when you tried to compile this: Line 98 should read: writeln('There can''t be an operation sign at the end.'); You can't use " to delineate a string in Pascal.

For the input '1+2':
Before you started the convert2 procedure you had already read '1' and '+', so the procedure read '2' and summed 1 and 2. Then, at eoln, printed the result.

For the input '1+2+3':
Again, before starting convert2 you had alread read '1' and '+', then you read '2' and sum it, then you read '+' and quit the loop. Since '+' is not a numeric digit, you print 'error' and complain.


I think you need to throw away convert2 entirely and rethink your code. No one I know ever does this when I suggest it to them, but good programmers always do: get out a piece of paper and a pencil and draw yourself your problem. Solve it on paper. Once you know how to solve it yourself then it is much easier to tell the computer how to do it.

So, lets think about your problem quickly:

I have a line that looks like this:
1+2+3
How do I solve it myself?
I look at the first number: [B]1[/B]+2+3 I remember that as my current total.

I look at the next thing: 1[B]+[/B]2+3

Duoas 1,025 Postaholic Featured Poster

You should be making better use of functions. For example, convert would be better written as:

function convert( c: char ): integer;
  begin
  convert := ord( c ) - ord( '0' )
  end;

And then used thus: digit1 := convert( c ); Also, you don't need to specify stuff after the program name. Just say: program bbb; In the whole history of Pascal specifying I/O stuff there has only once or twice actually made any difference at all (back when computers were happy with 10K of memory), and never has anyone cared either way. Since you are using a Borland dialect you can just drop it...

You should make your eqn just a little longer, like string[ 80 ] or something, just in case...

The variable currentnotblank is totally superfluous... Just test to see if c <> blank and put then and else branches as needed...

I'm sorry... I'll analyze your code better tomorrow (after I've slept some more). It is pretty scattered and you are using a lot of variables.

This is a bit of a tough assignment for a new programmer --as you know nothing about how to organize an expression reader to handle operator precedence... so you'll have to do without. However, I'll give a hint: a proper calculator expression always has the form: expression ::= number [operator expression] or, as I expect you want it: expression ::= [expression operator] number What that means is that you can expect to read an expression …

Duoas 1,025 Postaholic Featured Poster

The windows progress bar displays the percent-complete in the center, so that is a good choice. Delphi status bars are a pain in the nose to use, but I think you can add a panel containing a progress bar... I don't think I would bother with the form caption.

The reason it takes so long to load is because you are using a TListView... sorry to say.

Take a look at the OnMouseMove event for mouse over stuff.
Also, the PlaySound Win32 function. You'll probably want to compile your sounds into your program, so you'll need to read up on using resources.

Your program is designed to read and write text files. Binary files are a no-no. You'll damage them irrevocably. To auto-append a specific extension, just test the filename once you've got it to see if it has an extension or not, and add it if not.

The filename itself is just a string, so add an underscore the usual way basename + '_' + intToStr( 12 ) + fileext Just because you can save a file named "foo.pdf" does not make it a PDF file. It is still just a plain-text file. Remember, PDF, etc. are binary files. RTF is a text file, but it is not your run-of-the-mill text file. Its contents have a specific format. Load one into Notepad to see.

Good luck.

Duoas 1,025 Postaholic Featured Poster

Glad to have helped. :)

Now I see why you are calling application.processMessages. I didn't realize you were loading super-gigantic lists.

However, doing so introduces a bug: what if the user clicks, say, Remove Duplicate Entries or (gasp) Clear List while processing messages before the list is finished loading? That's a serious problem! :'(

So, how long do you have to wait loading the largest imaginable list? If it is only several seconds or less, you should instead turn your cursor to crHourGlass and/or put up a little message saying something like "Please wait" --or even, if you want to get fancy, use a a progress bar.

If it is longer, disable all the buttons that can affect the list before beginning to load, and call processMessages as you were during the load, then re-enable all the disabled buttons after loading. Or something like that.

Good luck. :cool:

Duoas 1,025 Postaholic Featured Poster

This is a math problem. You want to separate a number into hundreds.

141251 / 100 = 1412 R 51

and

1412 / 100 = 14 R 12

and

14 / 100 = 0 R 14

The C++ remainder operator is %.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Replied in kind. Lots of little fixes, a couple big ones. Most by way of suggestion and organization.

Let me know if your problem disappears with the changes.

Duoas 1,025 Postaholic Featured Poster

The DJGPP is a 16-bit DOS compiler, and as such, will not likely keep up with the most recent C++ standards.

Either get Cygwin, which is a small Unix environment running under windows --it includes the most recent version of the GCC (gcc and g++ and a few other languages),

Or get MinGW, which is the GCC compiler but without the Unix environment. I personally prefer MinGW, but most people tend to like Cygwin better. You can compile both Cygwin and Windows-native applications using Cygwin. I think it is a little easier to install too...

Hope this helps.

Oh yeah, the << and >> are bitwise operators. << is shift-left and >> is shift-right.
The number 2 in binary is 0010 .
So 0010 << 2 (read the value 2 bit-shifted left two places) becomes 1000 .
Likewise, 0010 >> 1 is 0001 .
It is possible to shift too far. 0010 >> 2 is 0000 (the 1 got pushed off the end).

In C++, the << and >> operators suggested themselves to putting something in an output stream: cout << "Hello there"; and getting something from an input stream: cin >> my_int; They are still actually shift operators, but they have been overloaded to do something else. C++ doesn't prevent that. You could, for example, overload the + operator to do multiplication. It would just confuse everyone...

Duoas 1,025 Postaholic Featured Poster

Your drawing should have a little arrow pointing from a variable named first in the main() function to the beginning of your list. ;-)

I like your new avatar, btw.

Duoas 1,025 Postaholic Featured Poster

I've looked over the sources you sent me again and I can't see why it shouldn't work.

CodeGear bought Borland's Delphi and C++ IDE/compilers, so you are actually using Delphi 2007 (the latest version) to compile your code.

The OnClick for Button12 is properly set to Button12Click in the DFM file, and the procedure itself does: lines_per_block := strToInt( edit6.text ); if saveDialog1.execute then so there is no valid reason why the dialogue shouldn't appear... except if edit6 contains an invalid number.

Why don't you change the first line to this and see if it catches the error:

try lines_per_block := strToInt( edit6.text )
except
  showMessage( 'You must specify how many lines to save per file' );
  edit6.setFocus;
  exit
end;

If that doesn't fix it then I'm completely baffled...

Duoas 1,025 Postaholic Featured Poster

Eh, sorry for the double post. Here're your problems (yes, more than one) with delet().

Line 24: ptr never becomes NULL unless you are trying to delete the last element.

However, that leaves a list like this
[1] points to [2]
[2] points to [3]
[3] was deleted!
That's a segmentation fault waiting to happen.

I want you to think about this one a bit instead of just giving you the answer. Please do as I ask and get out a piece of paper and pencil and draw yourself a little linked list, full of arrows and everything, and work your way through removing/deleting an element cleanly. Once you understand how to do it on paper you'll be able to tell the computer how to do it with ease.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Er, before anything else, you really need to watch your I/O. Don't mix C++ and C.
Find every getch() (non-standard evil!) and replace it with cin.get(); . Find every gets(s); and replace it with getline( cin, s ); .

Also, I know everyone teaches and tutorials and etc. this, but try not to use cin>>myint; when getting user input. Better to do what the user expects and head-off any input problems by getting a temporary string and converting it:

#include <sstream>
#include <iostream>
using namespace std;

int main() {
  string s;
  int i;

  cout << "Please enter an integer> ";
  getline( cin, s );

  if (!(stringstream( s ) >> i))
    cout << "That wasn't an integer!\n";
  else
    cout << "Thank you\n";

  return EXIT_SUCCESS;
  }

This code is very forgiving about input errors (gets a number whenever it can) and never leaves the input stream messed up.


OK, your linked list. You add a first for the first, then you add an x for every additional. However, you are still modifying first, not x in your input statements. Notice that when you display() the list the last one you entered is displayed properly, but all the others are garbage?

Also, you have memory leaks. What if the user chooses '1' twice? You should initialize first to NULL before anything else in your program. Then check it at the case 1 to see if it is still NULL. If not, you need to either delete …

Duoas 1,025 Postaholic Featured Poster

Yes, it gives the dialogue and all.

Ah, I forgot to mention that your program shouldn't have compiled at all because you had listed in your uses clause unit1 instead of unit1_helpme. So I'm not sure exactly what is wrong.

I used Delphi 5 to compile it. You said you were using FPC? Give me a day and I'll see if I can make it work with FPC.

Duoas 1,025 Postaholic Featured Poster

You sent that to me so quickly I took a look at it already. I still can't reproduce your error --the program works fine for me.


Testing
Are you sure you are saving in the same directory you loaded from? Here is what I did:
click "Load List", select my input file "in.txt". The list loads.

My list had twelve items, so I put something like 5 in the edit box. (I also tested with 4. As part of your error checking you need also to make sure that the number in the edit box is strictly greater than 1.)

I click "Go" to save. I select the same directory I loaded from and type an output file name "out.txt". Using explorer (or the command prompt) I look at the directory and I see three files:
- out1.txt
- out2.txt
- out3.txt
Examining the files shows they are properly formed.

The load and save directory need not be the same. Even if you load something the save directory is still at the default directory. You can force them to match by saying saveDialog1.initialDir := extractFileDir( openDialog1.filename ); before calling saveDialog1.execute.


Some errors
My debugger complained about a couple of things, so I looked them over. They are all in Button1Click. Here it is fixed:

procedure TForm1.Button1Click(Sender: TObject);  // load/open file
  var
    txt : TextFile;
    Buffer : String;
  begin
  if openDialog1.Execute() then  //(1)
    begin
    AssignFile(txt, openDialog1.FileName);
    Reset(txt); …
Duoas 1,025 Postaholic Featured Poster

I can't reproduce your error. If you can't figure it out by tomorrow then go to your project directory, zip everything up, and send it to me at michael thomas greer (without the spaces)
my provider is comcast.net Use whatever compression program you like (ZIP, TGZ, RAR, etc.) I won't take EXEs though.

Duoas 1,025 Postaholic Featured Poster

It works, it just doesn't tell you it did. Check your directory for files.

Remember also that the TListView must be populated with at least one item for it to work. (You loaded your list so that's not a problem.) When I did it, I just added three items using the designer, set the number of items per file to 2, and clicked the button --producing two files (the first containing two lines and the last containing one). I'm sure you must have a ton of files in the directory you saved to.

Most programs indicate that a save worked successfully by putting a message on the statusbar or changing the main form's caption or some other like thing.

Another thing you should be aware of is that there is currently no error checking to make sure that Edit6 contains a number, so if the user puts in "fooey" the program will crash. Go ahead and try it. There are several ways to fix this, but the easiest is something like:

try
  lines_per_block := strToInt( edit6.text )
except
  showMessage( 'You must specify how many lines to save per file.' );
  edit6.setFocus;
  exit
  end;
if saveDialog1.execute then ...

Glad to be of help.

Duoas 1,025 Postaholic Featured Poster

OK, that was enough. You need two changes.

In your class definition:

private
    { Private declarations }
    procedure saveNLines(filename: string; items: tListItems; startAt: integer; numLines: integer);
  public
    { Public declarations }
  end;

You must declare your procedures and functions before you can use them. Also, the compiler was complaining about passing the TListView.items as a var argument, so you will notice that I removed the var from the parameter list. The actual procedure definition must match, so change it below the same way:

procedure TForm1.saveNLines(filename: string; items: tListItems; startAt: integer; numLines: integer);

That compiled and worked correctly for me.

Duoas 1,025 Postaholic Featured Poster

Yeah, I know. I've gone through the same things... Over and over and over again. It's just part of programming...

Post your entire unit and I'll take a look-see. It has to be something painfully silly.

I once spent an entire week on about 60-70 lines of C code and was just at the point of burning my PC when I figured out that I had misplaced a } somewhere. Most. Obnoxious. Error. Ever.

Things get better after a while. Honest they do. Just don't give up. (Right now I'm banging my own head against the windows console... the stupid thing doesn't have a WndProc, permit event hooks, anything... it is for all intents and purposes an actual GUI-less process. All I want to know is if the user grabs the window and sizes it... but apparently that "can't happen". Alas...)


I think you put the saveNLines inside your TForm1 class definition, but defined it below as procedure saveNLines( ... ); instead of procedure TForm1.saveNLines( ... ); I'm not sure what the second error is, so post everything so I can find it.