CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12

Thread: Lpctstr*

  1. #1
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    56

    Lpctstr*

    A little confused by this.
    Im receiveing this type as a parameter and it should contain names. The way i read it is its an array of pointers to a string.
    Code:
    LPCTSTR*	names;
    names[0] = "jack";
    names[1] = "bob";
    // is the above acceptable?
    I think i just need a little tutorial on how to treat this type.
    Thx.

  2. #2
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    What you really need to do is search through your compiler's
    header files. If you do this, you'll probably find something like
    this:
    #define LPCTSTR const char*
    Alright, it's not perfect, but it's good enough for our purposes.

    So, no, what you typed is wrong. LPCTSTR is just a const char *.

    LPCTSTR*, then, would be a char** ... but that doesn't actually
    give you any memory or anything.

    I think what you're trying to do is pass something to a function
    that takes a LPCTSTR* as an argument, right? To do that, all
    you need to do is create a two-dimensional array on the stack.
    Then pass that array to the function.

    Code:
    char names[10][10] = {"jack", "bob"};
    CallFunction(names);
    --Paul

  3. #3
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    56
    Thx Paul. That helps.
    Actually, what im doing is trying to parse this structure...
    struct FOO{
    int count
    LPCTSTR* names;
    LPCTSTR* addresses;
    }
    So im receiveing this structure from another module and i dont know how to deal with it.
    Im trying to format it like so....
    Code:
    TCHAR names[5];
    TCHAR address[5];
    for( i = 0; i< foo.count; ++i ) {
      names[i] = foo.names[i];
      addresses[i] = foo.addresses[i];
    }
    ...
    // loop doing this
    sprintf(buffer, "His name is %s and his address is %s.", names[i], addresses[i]);
    I get messed up with strings.

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449
    Originally posted by Clarke Kent
    Thx Paul. That helps.
    Actually, what im doing is trying to parse this structure...
    struct FOO{
    int count
    LPCTSTR* names;
    LPCTSTR* addresses;
    }
    So im receiveing this structure from another module and i dont know how to deal with it.
    Im trying to format it like so....
    Code:
    TCHAR names[5];
    TCHAR address[5];
    for( i = 0; i< foo.count; ++i ) {
      names[i] = foo.names[i];
      addresses[i] = foo.addresses[i];
    }
    I'm under the assumption that you have control over the FOO structure, i.e. how it is defined.

    The names and address TCHAR arrays are just that -- arrays of TCHAR. They are not pointers. In your loop, you are assigning a pointer value "foo.names[i]" to a single character, names[i]. This is incorrect. What you want to do is to copy all of the characters from foo.names[i] to the names character array (similarly with the address).
    Code:
    #include <string.h>
    TCHAR names[5];
    TCHAR address[5];
    for( i = 0; i< foo.count; ++i ) {
      strcpy( names, foo.names[i]);
      strcpy(addresses, foo.addresses[i]);
    //...  
    }
    Your program has also other problems.

    First, how long is each name? Is it a maximum of 4 characters (plus the NULL)? That is what your code suggests when you say names[5]. If you happen to have "Peter" as a name, you will be overwriting memory.

    Second, I would have defined a single structure that takes one name and one address, and have an array of those. The problem with your code is that you're assuming that the number of names matches the number of addresses. In your loop, you may access a valid name, but an invalid address field, possibly causing a crash. This is of course if you can solidly, without a doubt, verify that for each name, there is an address and vice-versa.

    But in general, the problem that I see is that string handling is too darn error prone and newcomers never have a comfortable time handling them. If you are coding in C++, you can relieve all of these problems by using std::string and std::vector instead of hard-coded arrays. Here is an example:
    Code:
    #include <string>
    #include <vector>
    #include <iostream>
    
    struct FOO
    {
       std::string name;
       std::string address;
    };
    
    typedef std::vector<FOO> NameAddressList;
    
    //...
    using namespace std;
    
    void WriteNames(const NameAddressList& alist)
    {
        for( int i = 0; i< alist.size(); ++i ) {
           cout << alist[i].name << endl;
           cout << alist[i].address << endl;
        }
    }
    
    int main()
    {
        NameAddressList nalist;
        FOO foo;
    
        // First name and address
        foo.name = "John";
        foo.address = "123 Main Street";
    
        // add it to vector
        nalist.push_back( foo );
    
        // Second name and address
        foo.name = "Mary";
        foo.address = "100 First Street";
        nalist.push_back( foo );    
    
        // Third name -- note that the address is empty
        foo.name = "A very long name of someone with no address";
        nalist.push_back( foo );    
        
        WriteNames(nalist);
    }
    With the code above you've

    a) solved the problem of having names and addresses of any size

    b) Your arrays are not fixed sized, since you are not using arrays

    c) solved the issue if there is no address that has been defined for a name, or vice-versa (since a std::string is "" if nothing has been defined).

    If you are coding in 'C', then you have to make provisions (in other words, write more code) for things such as names of unlimited (or maximum length), making sure you check you don't access invalid memory, etc. The code I wrote above takes care of all of those details (which is why it is really hard to go back to C coding when you have C++ with all of its niceties

    Regards,

    Paul McKenzie

  5. #5
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    Just one note on LPCTSTR. As you have noted, it's a string of TCHARS, so depending on whether your code is compiled as Unicode or not, it will have two different meanings.
    Code:
    #ifdef _UNICODE
    typedef wchar_t TCHAR;
    // for some compilers / platforms it's actually typedef unsigned short TCHAR;
    typedef const TCHAR *LPCTSTR;
    #else
    typedef char TCHAR;
    typedef const TCHAR *LPCTSTR;
    #endif
    So, if you want to remain correct for both Unicode and ANSI versions of your program, you would have to use something like the following (assuming, TCHAR is properly defined for your compiler and operating system):
    Code:
    typedef std::basic_string<TCHAR> tstring;
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  6. #6
    Join Date
    Sep 2000
    Location
    Russia
    Posts
    262

    Re: Lpctstr*

    Originally posted by Clarke Kent
    ... The way i read it is its an array of pointers to a string.
    Code:
    LPCTSTR*	names;
    names[0] = "jack";
    names[1] = "bob";
    // is the above acceptable?
    Here is how you should have written what you wanted:

    Code:
    LPCTSTR names[ 2 ];
    names[0] = "jack";
    names[1] = "bob";
    or (even better):

    Code:
    // In this case you may omit the array size
    LPCTSTR names[] = { "jack", "bob" };
    Morover, if you are not intended to modify the array you could make it static. In this case the latter example doesn't produce any code at all, while the former will still be initialized at run-time.

    The code that PaulWendt suggested
    Code:
    char names[10][10] = {"jack", "bob"};
    is a declaration/definition of two-dimensional array of arrays of ten chars each. That means despite "jack" is 4 chars long (plus 1 for tetminating zero), it will occupy 10 bytes anyway. The same thing with "bob" :-)

  7. #7
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    56
    This is all very helpful gentlemen, thank you; i really appreciate your time.
    To clarify...

    I'm under the assumption that you have control over the FOO structure, i.e. how it is defined
    Let's assume i do not.

    Then this is ok?
    Code:
    LPCTSTR* names = NULL;
    LPCTSTR* addresses = NULL
    for(i = 0; i < foo.count; i++){
       _tcscpy( names, foo.names[i] );
       _tcscpy( emails, foo.addresses[i] )
    }
    // loop
    ...
    sprintf(buffer, "His name is %s and his address is %s.", names[i], addresses[i]);
    Thx again!

  8. #8
    Join Date
    Apr 1999
    Posts
    27,449
    Originally posted by Clarke Kent
    This is all very helpful gentlemen, thank you; i really appreciate your time.
    To clarify...


    Let's assume i do not.

    Then this is ok?
    Code:
    LPCTSTR* names = NULL;
    LPCTSTR* addresses = NULL
    for(i = 0; i < foo.count; i++){
       _tcscpy( names, foo.names[i] );
       _tcscpy( emails, foo.addresses[i] )
    }
    No this will not work. You are attempting to copy characters to NULL ponters. Your program will crash. The solution is what I posted, plus the caveats and potential problems in doing it the way I posted.
    Code:
    TCHAR names[5];
    TCHAR addresses[5];
    for(i = 0; i < foo.count; i++){
       _tcscpy( names, foo.names[i] );
       _tcscpy( addresses, foo.addresses[i] )
    }
    But you should seriously consider using std::string instead of these constructs.

    Regards,

    Paul McKenzie

  9. #9
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    Originally posted by Paul McKenzie
    No this will not work. You are attempting to copy characters to NULL ponters. Your program will crash.

    But you should seriously consider using std::string instead of these constructs.

    Regards,

    Paul McKenzie
    No offense to the original poster, but in my opinion, you ought to
    read up on pointers and arrays. Yeah, I'd suggest going "back
    to basics" as it were. It's one thing to not know the value of a
    #define; it's quite another to not understand something that's
    so fundamental to the language. If you don't understand pointers
    now, there is a lot you'll miss out on down the road. I suggest
    you go through tutorials, take some classes, read some books, or
    do whatever it is you need to in order to learn this stuff.

    --Paul

  10. #10
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    56
    do whatever it is you need to in order to learn this stuff
    What the he!! do you think im doing here?

  11. #11
    Join Date
    Apr 1999
    Posts
    27,449
    Originally posted by Clarke Kent

    What the he!! do you think im doing here?
    To be honest, you can't learn C++ by browsing or asking questions on a website. You must get books (and good ones) to learn the language correctly.

    Regards,

    Paul McKenzie

  12. #12
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    Originally posted by Clarke Kent

    What the he!! do you think im doing here?
    Yeah, similar to what Paul McKenzie said, we're not paid
    instructors and I certainly don't have the time to give you
    tutorials on the ins-and-outs of pointers. That is such a
    basic part of the language, I think it's best if you learn it from a
    textbook.

    It's great to ask questions on here. What's not great is when one
    question leads to another question, which leads to another
    question, which leads ... etc. When stuff starts getting like that,
    I start recommending books.

    --Paul

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured