473,386 Members | 1,654 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

character pointer to string

I know what is pointer, but I always blurred by character pointer to string. Can you tell me these accordingly ? Thanks.

What is the difference ?
char string[] = "abc"; // between this one and
char * string = "abc";

How come ?
This one work
Expand|Select|Wrap|Line Numbers
  1. const char * get()
  2. {
  3.     return "xyz";
  4. }
  5.  
  6. int main()
  7. {
  8.     printf("%s",get());
  9.     return 0;
  10. }
  11.  
But this one print out weird characters.
Expand|Select|Wrap|Line Numbers
  1. const char * get()
  2. {
  3.     string str = "xyz";
  4.     return str.c_str();
  5. }
  6.  
  7. int main()
  8. {
  9.     printf("%s",get());
  10.     return 0;
  11. }
Using std::string seems to be easier to manage but, what is the drawback of using std::string compare to char string[] ? Thanks.
Jul 7 '07 #1
11 5291
weaknessforcats
9,208 Expert Mod 8TB
Let's start here:
char string[] = "abc"; // between this one and
char * string = "abc";
The first is a local array of of 4 char containing abc and a null terminator.
The second is a pointer to a const array cotaining abc and a null terminator.

You canmake changes to the local array but you will crash trying to change the contents of the literal.

Remember, in C and C++, the name of the array is the address of element 0.
So, in both cases, the name string is the address of element 0 of the array. Therefore, the name string is a char* in both cases.

const char * get()
{
return "xyz";
}
This works because you are returning the address of the x. The literal is kept in the static memory pool and will exist after the function has completed.

const char * get()
{
string str = "xyz";
return str.c_str();
}
This fails because str is a local variable. It is kept in an area call a stack frame. The stack frame for a function contains all of the function arguments that were passed in plus all of the local variables and some other stuff. The stack frame is created when the function is called and destroyed when the function completes. With that in mind, here you are returning a char* that points to the x. Unfortunately, when the function completes, the stack frame is destroyed and the string str is returned to free memory. Those strange characters are whatever is in memory at the time you did the display.

This is a particularly bad bug. You see, memory isn't destroyed. It's just reused. That means returning a pointer to a local variable may actually work until that memory is reused. One time the program works, then next time it doesn't. The hard rule is to never return a pointer or a reference to a local variable.
Jul 7 '07 #2
This works because you are returning the address of the x. The literal is kept in the static memory pool and will exist after the function has completed.
Thanks the explanation is very helpful. if the address of the x ONLY is returned why does the y and z get printed as well ? is the address of the y and z same as the x ?
Jul 7 '07 #3
Thanks the explanation is very helpful. if the address of the x ONLY is returned why does the y and z get printed as well ? is the address of the y and z same as the x ?
Because it's an array. You only need to return the address of the first element, the array can automatically access the rest of the elements because they come right after the first element in memory. Like was said, the name of an array is actually a pointer to the first element, so it's the same as that.
Jul 7 '07 #4
scruggsy
147 100+
Thanks the explanation is very helpful. if the address of the x ONLY is returned why does the y and z get printed as well ? is the address of the y and z same as the x ?
Because of the way printf handles character arrays.
When you declare a string literal like "xyz", a non-printing NULL character is appended to the string to mark the end. So your string actually has 4 characters, and looks like this: "xyz\0" where "\0" represents the NULL.
When you pass a char pointer to printf, it starts at the first element and continues printing each character in sequence until it encounters that NULL.
Jul 7 '07 #5
weaknessforcats
9,208 Expert Mod 8TB
Maybe further explanation.

An array is required to be contuguous in memory:

x y z \0

So if you have the address of the x, the char y is next door, z after that and finally the null terminator.

An array of char that has a final elemnet of 0 (\0), is called a C-string. Many functions with char* arguments assume the \0 is there so they process until they reach it. If it's not there, your program goes into the weeds.

If your is not an array of char, or is an array of char but does not have the null terminator, you will need to have the number of elements in addition to the address of the first char.

All arrays that are not arrays of char require the number of elements be known.

Lastly, you are using C++ and the string class. You should not be using printf() in C++. Use the << operator instead. Use string arguments rather than char* arguments.

The C++ string is a ton of code to manage an array of char. You can use the code already written or re-invent the wheel.
Jul 7 '07 #6
Because of the way printf handles character arrays.
When you declare a string literal like "xyz", a non-printing NULL character is appended to the string to mark the end. So your string actually has 4 characters, and looks like this: "xyz\0" where "\0" represents the NULL.
When you pass a char pointer to printf, it starts at the first element and continues printing each character in sequence until it encounters that NULL.
Thanks now I am clearer. My simple class below is not working, it print out the strange characters. Is it because
m_url.substr(nStart) return a copy of string "/mail/"
and "mail" is converted into C Null-terminated string,
the string is local to the function getFileName and it's destroyed as the function return. or am I wrong ? Thanks.

url.h

Expand|Select|Wrap|Line Numbers
  1. #include <string>
  2.  
  3. using namespace std;
  4.  
  5. class Url 
  6. {
  7. public:
  8.     Url(const char *);
  9.     const char *  getFileName() const;
  10.  
  11. private:
  12.     string m_url;
  13. };
url.cpp
Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include "url.h"
  3.  
  4. Url::Url(const char * url)
  5. {
  6.     m_url = url;
  7. }
  8.  
  9. //Get filename of the url e.g www.yahoo.com/mail/
  10. //will return /mail/
  11. const char * Url::getFileName() const
  12. {
  13.     int nStart;
  14.     char * scheme = "://";
  15.     if((nStart = m_url.find(scheme,0)) == string::npos )
  16.     {
  17.        ......
  18.         return    m_url.substr(nStart).c_str();
  19.     ........
  20.         }
  21.         .......
  22.     .......
  23.  
  24. }
  25.  
  26. int main()
  27. {
  28.     Url url("www.yahoo.com/mail/");
  29.     cout << url.getFileName();
  30.     return 0;
  31. }
Jul 7 '07 #7
weaknessforcats
9,208 Expert Mod 8TB
There were various bugs. This works.

1)I removed the char* and replaced them with string. You can always go back to char*.
2) I changed Url::getFileName() to do the substr only if the substr was found. Otherwise return an empy string.
3) You need to add 3 to nStart because the copy starts with the beginning of the sub-string, which was 3. I would add an argument for this to remove the hard-coded 3. That way you can use the function for different scheme. The scheme itself should be an argument.
4) Watch those naming conventions. nStart does not have to be an int.
Ditto for m_url. m_ does not mean a member variable. This silliness started at Microsoft by C programmers. A member variable is
this->variablename. A global variable is ::variablename and a local variable is variablename. The compiler can verify all of these.

Anything the compiler can't verify is a weakness.
Expand|Select|Wrap|Line Numbers
  1.  
  2. class Url 
  3. {
  4. public:
  5.     Url(string url);
  6.     string  getFileName() const;
  7.  
  8. private:
  9.     string m_url;
  10. };
  11.  
  12.  
  13. //url.cpp
  14.  
  15. //Code: ( text )
  16. #include <iostream>
  17. //#include "url.h"
  18.  
  19. Url::Url(string url)
  20. {
  21.     m_url = url;
  22. }
  23.  
  24. //Get filename of the url e.g www.yahoo.com/mail/
  25. //will return /mail/
  26. string Url::getFileName() const
  27. {
  28.     int nStart;
  29.     string scheme = "://";
  30.     if((nStart = m_url.find(scheme,0)) != string::npos )
  31.     {
  32.       // ......
  33.                return  m_url.substr(nStart + 3);
  34.     //........
  35.         }
  36.      //   .......
  37.    // .......
  38.     return string();  //not found
  39.  
  40. }
  41.  
  42. int main()
  43. {
  44.     Url url("http://www.yahoo.com/mail/");
  45.     string result = url.getFileName();
  46.     if (result.size())
  47.     {
  48.     cout << result << endl;
  49.     }
  50.     else
  51.     {
  52.         cout << "Not Found" << endl;
  53.     }
  54.     return 0;
  55. }
  56.  
Jul 7 '07 #8
Thanks, I really learn lots from you today. It's important to have the class Url working, but it's even more important for me to understand why the class does not work previously, can you verified what I have asked previously is correct or wrong ?

The fourth one, so you mean using the this->variablename, ::variablename, variablename naming conventions is a better one ? it looks looks so graceful to me as well. Thanks.
Jul 7 '07 #9
weaknessforcats
9,208 Expert Mod 8TB
The maain error was here:
if((nStart = m_url.find(scheme,0)) == string::npos )
{
......
return m_url.substr(nStart).c_str();
........
Here the the substring was copied only if the scheme was not found. It should have been:
Expand|Select|Wrap|Line Numbers
  1. if((nStart = m_url.find(scheme,0)) != string::npos )
  2.     {
  3.        ......
  4.         return  m_url.substr(nStart).c_str();
  5.     ........
  6.  
Also, on this:
The fourth one, so you mean using the this->variablename, ::variablename, variablename naming conventions is a better one ?
This is not a naming convention. This is C++ code. this is a C++ keyword for the address of the object, -> is the C++ indirection operator, and :: is the C++ scope resolution operator.
Jul 7 '07 #10
Sorry, I have not shown the important part, the actual code is like these. if the url is www.yahoo.com/mail/ the function should return /mail/
But what I get printed out is weird "h !!" characters. Thanks so much.

Expand|Select|Wrap|Line Numbers
  1. const char * Url::getFileName() const
  2. {
  3.     int nStart;
  4.     char * scheme = "://";
  5.     if((nStart = m_url.find(scheme,0)) == string::npos ) // protocol http:// or https:// not found
  6.     {
  7.         if((nStart = m_url.find("/")) == string::npos)
  8.         {
  9.             return "/";
  10.         }
  11.         else
  12.         {
  13.             return    m_url.substr(nStart).c_str();
  14.         }
  15.     }
  16.     else 
  17.     {
  18.         nStart += strlen(scheme);
  19.         if((nStart = m_url.find("/",nStart)) == string::npos)
  20.         {
  21.             return "/";
  22.         }
  23.         else
  24.         {
  25.             return m_url.substr(nStart).c_str();
  26.         }
  27.     }
  28. }
  29.  
  30. int main()
  31. {
  32.     Url url("www.yahoo.com/mail/");
  33.     cout << url.getFileName();
  34.     return 0;
  35. }
  36.  
Jul 7 '07 #11
weaknessforcats
9,208 Expert Mod 8TB
This code:
m_url.substr(nStart).c_str();
doesn't work. True, m_url(nStart) returns a string but unless you capture that string it won't exist long enough to do the c_str() method.

You have to:
Expand|Select|Wrap|Line Numbers
  1. string answer =  m_url.substr(nStart);
  2. const char* result = answer.c_str();
  3.  
But if your return the result, the answer string dies with the function and you again will get garbage in main().

I say again, the only safe way is to return a string. The string that is returned is a COPY of the string in the function. The same is true of the char*. When returned, it is a COPY of the char* inside the function. If the char* referred to a local variable, then that variable is not there after the function completes.

If you still insist on a char*, you will need to allocate memory yourself and delete it later (if you remember and if it is safe -- here starts memory management issues):
Expand|Select|Wrap|Line Numbers
  1. char* result = new char[answer.size() + 1];
  2. strcpy(result, answer.c_str());
  3.  
and you have converted C++ back to C.
Jul 8 '07 #12

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: rusttree | last post by:
I'm working on a program that manipulates bmp files. I know the offset location of each piece of relevent data within the bmp file. For example, I know the 18th through 21st byte is an integer...
4
by: christopherlmarshall | last post by:
I have gotten in the habit of using strings to manage character buffers that I pass in to unix system calls. For example, suppose I want to create a character buffer to use with the "write"...
14
by: Charles L | last post by:
I don't know if this is a stupid quesiton or not. I would like to know how to convert an array of characters generated from a previous operation to a string ie how do I append a null character at...
8
by: Sharon | last post by:
hi, I want to compare character, if the string contains character "-" then it will print Hello on the screen however, neither method (1) nor method (2) work in the code below: so what the correct...
8
by: Dawn Minnis | last post by:
Hey guys If I have a program (see codeSnippet1) that I compile to be called test.o Then run it as test.o n n 2 3 4 I want the code to be able to strip out the two characters at the start...
3
by: linguae | last post by:
Hello. In my C program, I have an array of character pointers. I'm trying to input character strings to each index of the character pointer array using scanf(), but when I run the program, I get...
4
by: n_jaksic | last post by:
I need to store heterogeneous data (for example, a string, a vector of floats and some ints) in an unsigned character array, for the purpose of storing information in some header. I then need to...
14
by: Shhnwz.a | last post by:
Hi, I am in confusion regarding jargons. When it is technically correct to say.. String or Character Array.in c. just give me your perspectives in this issue. Thanx in Advance.
14
by: Lambda | last post by:
I'd like to create separate character pointers, pass them to a function to assign each one different value, and assign the pointers to an array. But when I try: #include <stdio.h> #include...
19
by: bowlderyu | last post by:
Hello, all. If a struct contains a character strings, there are two methods to define the struct, one by character array, another by character pointer. E.g, //Program for struct includeing...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.