Strings vs char* and strcpy()

S

stroker_ace

Hi,

I wonder if anyone could point me in the direction of a discussion on
the similarities and differences between the C++ String type and char*
strings?

The reason I ask is because I am working on a legacy application using
the old C socket.h library. The send function accepts the message to be
sent as a char*.

I am having problems making a deep copy of a char* string in C++.

Consider the following code sample:

class Message {

public:

Message () : unsent(NULL) {
};

void Add(char*);
void Del();
char* GetMsg();
void ShiftMsg(int);

~Message() {
Del();
}

private:

char* wholeMessage;
char* unsentBytes;

};

//Create deep copy of inmessage
void Message::Add (char* inmessage) {

wholeMessage = new char[strlen(inmessage) + 1];

strcpy(wholeMessage,inmessage);

unsentBytes = wholeMessage;

}

//Release memory allocated to wholeMessage
void Message::Del() {

if (wholeMessage != NULL) {
delete [] wholeMessage;
}
unsentBytes = NULL;

}

//Get unsent portion of message
char* Message::GetUnsent() {

if (unsentBytes == NULL) {
return "";
}
else {
return unsentBytes;
}
}

//Increment unsentBytes pointer to point at unsent portion of
//message
void Message::ShiftMsg(int bytesSent) {
unsentBytes = unsentBytes + bytesSent;
}


I have a problem. When I attempt to allocate the momory for
wholeMessage using the new operator I get an access violation yet I do
not understand why. Can anyone explain what I am doing wrong?

I realise that I probably *should* be using C++ String types to store
my message. I know that I can allocate a char* to a String variable but
does it work the other way round? Can I pass a String to a function
expecting a char*

Finally, a question about general style. I feel I should be creating a
new instance of Message for each string I am processing and destroying
it once sent but this would involve me creating and destroying hundreds
of instances a second. Is there a large overhead involved in doing
this?

Many thanks for any help.

Lawrie.
 
S

Srini

I realise that I probably *should* be using C++ String types to store
my message. I know that I can allocate a char* to a String variable but
does it work the other way round? Can I pass a String to a function
expecting a char*

Use string's cstr method to get the C char* from a string object.
Sorry I am answering one of your questions. I am not sure of the other
answers myself.

Srini
 
P

Prawit Chaivong

Hi,

I wonder if anyone could point me in the direction of a discussion on
the similarities and differences between the C++ String type and char*
strings?

The reason I ask is because I am working on a legacy application using
the old C socket.h library. The send function accepts the message to be
sent as a char*.

I am having problems making a deep copy of a char* string in C++.

Consider the following code sample:

class Message {

public:

Message () : unsent(NULL) {
};

void Add(char*);
void Add(const char *); // would be better.
void Del();
char* GetMsg();
const char* GetMsg(); // would be better, to prevent modifying msg
//outside this class
void ShiftMsg(int);

~Message() {
Del();
}

private:

char* wholeMessage;
char* unsentBytes;

};

//Create deep copy of inmessage
void Message::Add (char* inmessage) {

wholeMessage = new char[strlen(inmessage) + 1];
inmessage need to be checked whether it's NULL or not.
Because strlen doesn't check. and it would crash if inmessage is NULL.
strcpy(wholeMessage,inmessage);

unsentBytes = wholeMessage;

}

//Release memory allocated to wholeMessage
void Message::Del() {

if (wholeMessage != NULL) {
delete [] wholeMessage;
}
unsentBytes = NULL;

}

//Get unsent portion of message
char* Message::GetUnsent() {

if (unsentBytes == NULL) {
return "";
}
else {
return unsentBytes;
}
}

//Increment unsentBytes pointer to point at unsent portion of
//message
void Message::ShiftMsg(int bytesSent) {
unsentBytes = unsentBytes + bytesSent;
}


I have a problem. When I attempt to allocate the momory for
wholeMessage using the new operator I get an access violation yet I do
not understand why. Can anyone explain what I am doing wrong?

I realise that I probably *should* be using C++ String types to store
my message. I know that I can allocate a char* to a String variable but
does it work the other way round? Can I pass a String to a function
expecting a char*

Finally, a question about general style. I feel I should be creating a
new instance of Message for each string I am processing and destroying
it once sent but this would involve me creating and destroying hundreds
of instances a second. Is there a large overhead involved in doing
this?

Many thanks for any help.

Lawrie.
 
I

Ian

I have a problem. When I attempt to allocate the momory for
wholeMessage using the new operator I get an access violation yet I do
not understand why. Can anyone explain what I am doing wrong?
Is inmessage NULL terminated?
I realise that I probably *should* be using C++ String types to store
my message. I know that I can allocate a char* to a String variable but
does it work the other way round? Can I pass a String to a function
expecting a char*
string.c_str() does this.
Finally, a question about general style. I feel I should be creating a
new instance of Message for each string I am processing and destroying
it once sent but this would involve me creating and destroying hundreds
of instances a second. Is there a large overhead involved in doing
this?
There will be an overhead, it's up to you to decide if it is too high.
Try the most simple thing that will work, optimise if you have to.

Ian
 
S

stroker_ace

The add method crashes with an access violation if inmessage is not
NULL.

The line

wholeMessage = new char[strlen(inmessage) + 1];

seems to cause the problem but I don't understand why I am getting an
access violation.
 
S

stroker_ace

I believe inmessage is null terminated but even if it is not should
this cause a problem?

my new statement allocates a char array 1 byte bigger than the value
returned by strlen so there is enough space for the null termination
character.
 
R

Rolf Magnus

The add method crashes with an access violation if inmessage is not
NULL.

The line

wholeMessage = new char[strlen(inmessage) + 1];

seems to cause the problem but I don't understand why I am getting an
access violation.

Is inmessage a valid C style string, i.e. is it terminated with a '\0'
character?
 
S

stroker_ace

On examination it would appear that inmessage is NOT '\0' terminated.

I don't understand why this is causing a problem when I allocate memory
though.
 
P

Prawit Chaivong

I believe inmessage is null terminated but even if it is not should
this cause a problem?

my new statement allocates a char array 1 byte bigger than the value
returned by strlen so there is enough space for the null termination
character.

Could you show us a callstack?
 
J

Jakob Bieling

On examination it would appear that inmessage is NOT '\0' terminated.

I don't understand why this is causing a problem when I allocate
memory
though.


strlen determines the length by looking for the 0-char. You do not
get the access violation because you allocate memory. You get it,
because you pass a non-0-terminated char array, which, if you read the
documentation, is not what strlen expects.

hth
 
S

stroker_ace

I have added a few lines of debug, checked the String inmessage for
'\o' chars and output the length returned by strlen BEFORE attempting
to allocate memory.

inmessage IS null terminated and strlen returns a valid length.

I am still at a loss to determine why I am getting the access violation.
 
S

stroker_ace

Please disregard the previous post.

The char* inmessage is definately null terminated.

In a debug example strlen returns 71.

I therefore allocate a new char[72] which is big enough for the string
plus the /0 char.

I cannot understand how this is causing the access violation.
 
S

stroker_ace

Okay, I have been experimenting with my code and have changed the ADD
method as follows:

void Message::Add (const char* inMessage) {

STD_TRY()

if (strchr(inMessage,'\0') != NULL) {
cout << "NULL TERMINATED\n";
}

cout << "strlen: " << strlen(inMessage) << "\n";
cout << "sizeof: " << sizeof inMessage << "\n";

if (inMessage != NULL) {
cout << "allocating\n";
wholeMessage = new char[10];
cout << "Allocated\n";
// wholeMessage = new char[strlen(inMessage) + 2];
// strcpy(wholeMessage,inMessage);
}
else {
wholeMessage = "";
cout << "Message::Add, NULL char* received\n";
}

unsentBytes = wholeMessage;

STD_CATCH("Message::Add")

} //Message::Add

Where STD_TRY() and STD_CATCH() are used to catch any exceptions.


Here is the output:

NULL TERMINATED
strlen: 71
sizeof: 4
allocating
Error in method: Message::Add
%SYSTEM-F-ACCVIO, access violation [blah blah blah]

As you can see I am simply trying to allocate a fixed size block of
memory without any calls to strlen() or strcpy() and I am still getting
an access violation.
 
T

Tim Love

if (strchr(inMessage,'\0') != NULL) {
cout << "NULL TERMINATED\n";
}
Is this worth doing? In what circumstances do you think
"NULL TERMINATED\n" wouldn't be printed out?

As you can see I am simply trying to allocate a fixed size block of
memory without any calls to strlen() or strcpy() and I am still getting
an access violation.
This may be because of some earlier memory allocation problem. Something
like http://valgrind.org/ may be of use.
 
O

Old Wolf

class Message {
public:
Message () : unsent(NULL) { };
void Add(char*);
void Del();
char* GetMsg();
void ShiftMsg(int);

~Message() {
Del();
}
private:
char* wholeMessage;
char* unsentBytes;
};

//Create deep copy of inmessage
void Message::Add (char* inmessage) {
wholeMessage = new char[strlen(inmessage) + 1];
strcpy(wholeMessage,inmessage);
unsentBytes = wholeMessage;
}

I have a problem. When I attempt to allocate the momory for
wholeMessage using the new operator I get an access violation
yet I do not understand why. Can anyone explain what I am doing wrong?

Probably you have already corrupted the heap earlier in
the program. For example, Message's constructor does not set
wholeMessage to anything, and you don't have a valid
copy constructor or assignment operator.

Can you post a COMPLETE program that causes the crash?
 
R

Ron Natalie

Hi,

I wonder if anyone could point me in the direction of a discussion on
the similarities and differences between the C++ String type and char*
strings?

I can give you it in one word. Char* is NOT a string type. It's a
pointer to a single character. You need to convey other information
to use it as a pseudo-string type. You're responsible for allocating,
deallocation, copying, remembering the size, etc... separately from
just remembering where the first byte of the string is.
I have a problem. When I attempt to allocate the momory for
wholeMessage using the new operator I get an access violation yet I do
not understand why. Can anyone explain what I am doing wrong?

Your first problem is your class doesn't have a copy constructor or
copy assignment operator. Further, you don't initialize the two
pointers which means that your destructor does the wrong thing
(by the way delete of a null pointer is a no op, so your test
in Del is unnecessary).

You don't show how it is used, but are you sure inmessage is a null
terminated string as wella s not being a NULL pointer?
I realise that I probably *should* be using C++ String types to store
my message. I know that I can allocate a char* to a String variable but
does it work the other way round? Can I pass a String to a function
expecting a char*

Bingo. There is a function called c_str() as a member of std::string
that returns a const char*. If you need a non-const string, then you
will have to copy (although you might do the following):

std::string string = "yada yada yada";
const char* csp = string.c_str(); // ok, we have a const char*
// now make it writable.
std::vector<char> cv(csp, csp+string.size()+1);
function_requiring_charptr(&csp[0]);


Finally, a question about general style. I feel I should be creating a
new instance of Message for each string I am processing and destroying
it once sent but this would involve me creating and destroying hundreds
of instances a second. Is there a large overhead involved in doing
this?

You can add add a "Clear" function to your code that rather resets the
string rather than freeing memory.
 
P

Phil Endecott

if (strchr(inMessage,'\0') != NULL) {
cout << "NULL TERMINATED\n";
}

Remember what a char* is. It is just an address. You're imagining that
the memory is full of "objects". It's not, when you're dealing with it
at this level; it's just full of bytes. If inMessage is not null
terminated, strchr will just keep stepping through memory until it finds
a 0 (and they are quite common).

The code you have posted has all looked reasonable, though as others
have pointed out you could add a fews consts and so on. The bug in your
program is not in the code that you've posted. You'll need to post a
complete example that we can run and see the error. In the process of
creating a simple example you'll probably find the error yourself.

You might also like to try something like Purify or Valgrind.

--Phil.
 
S

Serge Paccalin

Le mercredi 8 juin 2005 à 13:51, (e-mail address removed) a écrit dans
comp.lang.c++ :
I have added a few lines of debug, checked the String inmessage for
'\o' chars and output the length returned by strlen BEFORE attempting
to allocate memory.

inmessage IS null terminated and strlen returns a valid length.

I am still at a loss to determine why I am getting the access violation.

From my experience, when a reasonable allocation attempt fails with an
access violation, it means that memory was corrupted at some point
before the allocation attempt; by writing outside the valid boundaries
of another memory block, you probably overwrote the data used by the
allocator to link memory blocks together and keep track of available
blocks.

Good luck.

--
___________ 08/06/2005 16:01:08
_/ _ \_`_`_`_) Serge PACCALIN -- sp ad mailclub.net
\ \_L_) Il faut donc que les hommes commencent
-'(__) par n'être pas fanatiques pour mériter
_/___(_) la tolérance. -- Voltaire, 1763
 
A

Andre Kostur

(e-mail address removed) wrote in @g49g2000cwa.googlegroups.com:
Okay, I have been experimenting with my code and have changed the ADD
method as follows:

void Message::Add (const char* inMessage) {

STD_TRY()

if (strchr(inMessage,'\0') != NULL) {
cout << "NULL TERMINATED\n";
}

cout << "strlen: " << strlen(inMessage) << "\n";
cout << "sizeof: " << sizeof inMessage << "\n";

if (inMessage != NULL) {
cout << "allocating\n";
wholeMessage = new char[10];
cout << "Allocated\n";
// wholeMessage = new char[strlen(inMessage) + 2];
// strcpy(wholeMessage,inMessage);
}
else {
wholeMessage = "";
cout << "Message::Add, NULL char* received\n";

Uh oh.... does your delete code take this case into account? If you try to
delete[] wholeMessage after this, game over. Anything can happen.

[snip]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top