I have a strange problem with c++ string object in my class on the line s.append(ptr2str ....);
class cRegexMatches {
public:
char *ptr2str;
int *pOffsets;
cRegexMatches() { ptr2str = NULL; pOffsets=NULL;}
void update(char *p, int *offsets) {
ptr2str = p; pOffsets = offsets;
printf("ptr2str=%p %s|\n", p, p);
}
string operator [] (int id) {
string s;
printf("operator[] %p %s|", ptr2str, ptr2str);
int i;
for (i=0; i<4; i++) printf(" %d", pOffsets[i]);
printf("\n");
if (!ptr2str) return s;
if (pOffsets[2 * id + 1] == 0) return s;
int len = pOffsets[2 * id + 1] - pOffsets[2 * id];
printf("size %d %ld before %s\n", s.size(), len, ptr2str + pOffsets[2 * id]);
s.append(ptr2str + pOffsets[2 * id], len);
cout << s << endl;
return s;
}
};
It runs fine with the follow code.
int main(int argc, char *argv[]) {
char *p = "10.20.0.111:8080";
int pInts[] = {0, 16, 0,16};
regmatches.update(p, &pInts[0]);
string s = regmatches[0];
int i;
for (i=0; i<s.size(); i++) {
printf("%c\n", s.c_str()[i]);
}
return 0;
}
But in my project, the line s.append(ptr2str + pOffsets[2 * id], len); seems to corrupt the first byte to be \x00, according to the debug statement printf(..) before s.append and the cout ... afterwards.
Any idea what caused the strange behavior? Thanks!
UPDATE 1
Thanks to #user657267's suggestion, here is a brief description on how the code was used in my project. It looks very innocent.
cRegexMatches globalVar;
//p points to some c string
//pInt points to an array of integers, in my case, it's 0, 16, 0, 16
globalVar.update(p, pInt);
cout << globalVar[0]
For now, I found a workaround: I changed the line s.append(ptr2str + pOffsets[2 * id], len); to return string(ptr2str + pOffsets[2 * id], len); and it worked fine. But I am still curious on what caused the strange behavior.
I believe that the problem might be your definition of the string in main.
char* p = "10.20.0.111:8080";
should be
char p[] = "10.20.0.111:8080";
Only the second definition reserves memory on the stack.
Related
I am still a newbie to c++; I was wondering why the code i wrote for a custom string split fuction does not work? (it splits by char and not string) I think there is something wrong with memcpy in the second instance?
char** strsplit(const char *s, const char splitboi)
{
const int LEN = length(s);
int segs = 0;
char *segstore, **out;
for (int chrs=0; chrs<=LEN; chrs++)
{
if(*(s+chrs) != splitboi)
{char* temp = chrs==0 ? (char*)"" : segstore;
segstore = new char[chrs+1];
memcpy(&segstore, &temp, sizeof(char*));
segstore[chrs] = *(s+chrs);}
else if(*(s+chrs) == splitboi)
{char **temp = out;
out = new char* [segs+1];
memcpy(&out, &temp, sizeof(char**)); //something wrong with this
out[segs] = segstore;
segs++;}
}
delete segstore;
cout << out[0] << '\n';
return out;
}
When I run the program, I get exception "heap has been corrupted" after completion of the function
I have read that this exception may cause if you are using memory that has been freed, or when you are writing to index which is out of array index. But none of the cases applies here. I have read other answers of some problems but it didn't help much.
`char fileNametoExport[26]="d:\\FOlder1\\part1.ipt";
char WorkingFolderName[260] ="d:\\folder";
int start = rFind(fileNametoExport, '\\');
int finish = rFind(fileNametoExport, '.');
if (start == -1)
start = 0;
char partname[260];
strcpy(partname,substr(fileNametoExport, start, finish));
::AfxMessageBox((LPCTSTR)partname);
char xtfile[260];
char xmltxtfile[260];
strcpy(xtfile, strcat(WorkingFolderName, partname));
strcat(xtfile, "__Default.x_t");
strcpy(xmltxtfile, WorkingFolderName);
strcat(xmltxtfile,"_XT_SE_INV_Default_SOLID_0_Solid1_xt.xmt_txt");`
function rfind() to find occurence of char in char array-
int rFind(char* s, char c)
{
int sz = 0;
char *tmp = s;
while (*tmp != '\0')
{
sz++;
tmp++;
}
for (int i = sz - 1; i >= 0; i--)
{
if (*(s + i) == c)
return i;
}
return -1;
}
function substr() to get substring from position x to y (y exclusive)
char* substr(char* s, const int b, const int f)
{
char *str = new char[f - b];
int t = 0;
for (int i = b; i != f; i++)
{
str[t] = s[i];
t++;
}
str[t] = '\0';
return str;
}
P.S- While giving input I ensure that fileNametoExport always contains '.' and '\'.
Your program do not check lengths of input strings. You can receive a string longer than your buffer and program will fail.
If your program get fileNametoExport = "d:\\somefolder\\somefilewithoutdot" , finish will be -1 and program fail at strcpy(partname,substr(fileNametoExport, start, finish)); .
Program writes after buffer in char* substr(char* s, const int b, const int f) at line
str[t] = '\0';
because t at this point equal f-b , size of str buffer.
Function _ASSERTE( _CrtCheckMemory( ) ); from <crtdbg.h> very useful when searching for bugs like this. Put it around suspicious code and it fails after your bug. It works only in debug.
I am trying to implement my own version of strncpy(), i found a source code from this link.
But I encountered a Unhandled exception at 0x00411ad5 in exercise 2.exe: 0xC0000005: Access violation writing location 0x00417800. everytime the code reaches this code while((x++ < n) && (*dest++ = *source++));
Here is the complete code:
char *strncpy(char * destination, const char * source, size_t n){
char *dest;
dest = destination;
size_t x=0;
while((x++ < n) && (*dest++ = *source++)); //this is where unhandled exception occurs
while(x++ < n){
*dest++ = 0;
}
return dest;
}
int main(){
char *sample = "blue";
char * sample2 = "red";
cout << strncpy(sample, sample2, 5);
getch();
return 0;
}
Please tell me why this occurs and how should I fix it? Thanks!
Your destination is "blue" which is a string literal, that is a constant. As such it is located in a read-only part of memory (and pointed at by local sample variable), thus error when writing.
Try this:
int main(){
char sample[] = "blue";
char * sample2 = "red";
cout << strncpy(sample, sample2, 5);
getch();
return 0;
}
which makes sample an array in local, writeable memory.
You cannot write to a string constant (sample); write to a char array instead:
int main(){
char *sample = "blue";
char buffer[5];
cout << strncpy(buffer, sample, sizeof(buffer));
getch();
return 0;
}
First, it was already explained to you that you can't overwrite a string that is defined like that.
Second, you cant use cout << strncpy if that function returns pointer to the end of the copied string.
There are two main problems with your program
The first one is that function strncpy has to return destination instead of dest
char *strncpy(char * destination, const char * source, size_t n){
char *dest;
dest = destination;
size_t x=0;
while((x++ < n) && (*dest++ = *source++)); //this is where unhandled exception occurs
while(x++ < n){
*dest++ = 0;
}
// return dest;
return destination;
}
The second one is that string literals are immutable. Any attempt to modify a string literal results in undefined behaviour.
Thus main function should be rewritten the following way
int main(){
char sample[] = "blue";
char * sample2 = "red";
cout << strncpy(sample, sample2, sizeof( sample ) );
getch();
return 0;
}
Also it is a bad style of programming to use variable with name x as a count. It is better to use for example i.
I would write the function simpler
char * strncpy( char *destination, const char *source, size_t n )
{
char *dest = destination;
while ( n-- && ( *dest++ = *source++ ) );
while ( n-- ) *dest++ = '\0';
return destination;
}
I am doing this
char *draw_line(int n, char ch)
{
char *line = new char[50];
for(int i = 0; i <= n; i++)
line[i] = ch;
return line;
}
and while calling the function I am writing this:
char *res_line = draw_line(50, '=');
cout<<*res_line;
but instead of getting = printed 50 times in the console window, it just show = sign one time. My main aim is to return the = or any character as many times I want and output
the same to a text file. That's it.
cout<<*res_line;
is printing one char because *res_line is char, not char*.
Write:
cout<<res_line;
But wait — that is not going to work either because res_line is NOT null-terminated.
Use std::string or std::vector<char> — avoid explicit memory allocation, use RAII idiom instead:
std::string draw_line(int n, char ch)
{
return {n, ch}; //C++11
}
So simple!
Or if you use std::vector:
std::vector<char> draw_line(int n, char ch)
{
return {n, ch}; //C++11
}
which is almost same.
In C++03, however, you've to write:
return std::string(n, ch); //in the first case
return std::vector<char>(n, ch); //in the second case
That is, invoke the constructor explicitly.
The valid code will look as
char* draw_line( int n, char ch )
{
char *ch2= new char[n + 1]();
std::memset( ch2, ch, n );
return ch2;
}
//...
char *ch50 = draw_line(50,'=');
cout << ch50;
//...
delete []ch50;
Take into account this statement
char *ch2= new char[n + 1]();
But it would be much better to write simply
std::cout << std::string( 50, '=' );
char* draw_line(int n, char ch)
{
char *ch2= (char *) malloc(sizeof(char)*(n+1)); // (n+1) here
for(int i=0;i<n;i++) // < instead of <=
ch2[i]=ch;
ch2[n] = 0; // terminator
return ch2;
}
char *ch50 = draw_line(50,'=');
cout<< ch50; // changed from *ch50 to ch50
ADDON: look at string-fill constructor
cout << string(50, '=');
Can someone tell me what's wrong with the following?
I'm trying to add characters to a character array. name is a pointer to a character array in the MyString class.
void MyString::add_chars(char* c)
{
if(l < strlen(c)+strlen(name))
name = resize(name, l, sizeof(c));
int i,j;
for(i=0; i<strlen(c); i++) {
name[i+l-1] = c[i];
l++;
}
}
char* MyString::resize(char* vptr, int currentsize, int extra) {
char* temp = new char[currentsize + extra];
int i;
for (i = 0; i < currentsize; i++) {
temp[i] = vptr[i];
}
vptr = temp;
return vptr;
}
And in main:
MyString g ("and");
g.add_chars("baasdf");
cout << g.get_name() << "\n";
But get_name returns "andb". How can I fix my code?
Edit:
Updated code, still same result..
void StringList::add_chars(char* c)
{
char* my_new_string = resize(name, l, sizeof(char));
if( my_new_string != NULL )
{
delete [] name;
name = my_new_string;
}
int i,j;
for(i=0; i<strlen(c); i++) {
name[i+l-1] = c[i];
l++;
}
name[l-1] = '\0';
}
char* StringList::resize(char* vptr, int currentsize, int extra) {
char* temp = new char[currentsize + extra + 1];
int i;
for (i = 0; i < currentsize; i++) {
temp[i] = vptr[i];
}
vptr = temp;
return vptr;
}
This line is wrong:
name = resize(name, l, sizeof(c));
You should not take the sizeof(char*), which your c variable is, but you should do sizeof(char) or just 1.
Also, make sure that you do +1 on the size to take care of the zero termination char at the end of your string.
How can I fix my code?
Don't fix it. Throw it away and use vector<char> or just string.
But I insist, how can I fix my code!?
OK, OK, here is how...
Get a nice debugger, for example this one.
Step carefully through the code, constantly inspecting the variables and comparing them with what you expect them to be.
When you reach the call to resize, take note of sizeof(c) (assigned to extra parameter of resize). When you realize it is not what you expected, ask yourself: what is the purpose of sizeof, and you'll understand why.
BTW, you also have a memory leak and a very poor performance due all these strlens.
Firstly, am I right in assuming that this is a learning exercise for you in learning "how to create your own string class"? C++ has already got a built-in string type which you should always prefer for the most part.
the sizeof operator yields the size (in bytes) of its operand, which in this case is c whose type is char* - it looks like what you're actually after is the length of a null-terminated character array (a "C" string") - you're already using strlen, so I'd suggest you simply want to use that again. (taking a null-terminator into account too)
name = resize(name, l, strlen(c) + 1);
Note, that your code looks as if it suffers from memory leaks. You're assigning a new value to your name variable without clearing up whatever existed there first.
if(l < strlen(c)+strlen(name))
{
char* my_new_string = resize(name, l, strlen(c));
if( my_new_string != NULL )
{
delete [] name;
name = my_new_string;
}
}
EDIT: As other replies have pointed out, there's still plenty wrong with the code which could be resolved using C++'s string and vector.
Here's one possible way you could implement add_chars
void MyString::add_chars(char* c)
{
if( c != NULL && name != NULL )
{
size_t newlength = strlen(c) + strlen(name) + 1;
char* newstring = new char[newlength];
if( newstring != NULL )
{
size_t namelength = strlen(name);
size_t remaining = newlength - namelength;
strncpy( newstring, name, newlength );
strncpy( &newstring[namelength] , c, remaining );
delete [] name;
name = newstring;
}
}
}