My C++ class is going over C-style strings and working with pointers. I'm to write a function that has three parameters: a char * s1, a const char * s2, and a size_t max, which represents that maximum size of the s1 buffer. I am to append the characters in s2 to the end of s1. The directions advise me to make sure there is only one '\0' at the end of the combined characters and I am not to go beyond the end of the buffer I'm asked to copy to. The function will return a pointer to the first character in s1.
I cannot use any functions in the standard library. What I can use are pointers, pointer arithmetic or array notation.
I've started, but not sure where to go.
const char * myFunction (char * s1, const char * s2, size_t max)
{
char * begin = s1;
while (*s1) s1++;
while ((s1 < begin + max - 1) && (*s2 != '\0')) {
*s1++ = *s2++;
}
return s1;
}
Not sure what to do after reaching the end of s1. How would I put s2 to the end of s1?
I cannot use any functions in the standard library.
The only required one would be strlen(), I think. Roll your own:
#define min(a,b) ((a) < (b)) ? (a) : (b)
size_t str_length(const char* s)
{
size_t len = 0;
for( ; *s; ++s, ++len);
return len;
}
const char * append (char * s1, const char * s2, size_t max)
{
if(!s1 || !s2) //If either of strings is NULL, nothing to be done
return s1;
size_t s1_length = str_length(s1);
if(s1_length < max - 1) //If there is a room in s1...
{
size_t s2_length = str_length(s2); //Get length of s2
size_t append_size = min(s2_length, max - s1_length - 1); //Make sure we won't copy more than buffer can hold
if(append_size > 0)
{
memcpy(s1 + s1_length, s2, append_size); //This will overwrite null terminator in 's1'
s1[s1_length + append_size] = 0;
}
}
return s1;
}
Test:
int main(void)
{
char dest[64] = "This is a test";
append(dest, " of strings appending", 64);
printf("%s (length: %d)\n", dest, str_length(dest));
append(dest, " of appending too long string, that will probably not fit inside destination buffer", 64);
printf("%s (length: %d)\n", dest, str_length(dest));
return 0;
}
Output:
This is a test of strings appending (length: 35)
This is a test of strings appending of appending too long strin (length: 63)
Here is working sample.
Related
#include<string>
#include<cstring>
class Solution {
void shift_left(char* c, const short unsigned int bits) {
const unsigned short int size = sizeof(c);
memmove(c, c+bits, size - bits);
memset(c+size-bits, 0, bits);
}
public:
string longestPalindrome(string s) {
char* output = new char[s.length()];
output[0] = s[0];
string res = "";
char* n = output;
auto e = s.begin() + 1;
while(e != s.end()) {
char letter = *e;
char* c = n;
(*++n) = letter;
if((letter != *c) && (c == &output[0] || letter != (*--c)) ) {
++e;
continue;
}
while((++e) != s.end() && c != &output[0]) {
if((letter = *e) != (*--c)) {
const unsigned short int bits = c - output + 1;
shift_left(output, bits);
n -= bits;
break;
}
(*++n) = letter;
}
string temp(output);
res = temp.length() > res.length()? temp : res;
shift_left(output, 1);
--n;
}
return res;
}
};
input string longestPalindrome("babad");
the program works fine and prints out "bab" as the longest palindrome but there's a heap overflow somewhere. Error like this appears:
Read of size 6 at ...memory address... thread T0
"babad" is size 5 and after going over this for an hour. I don't see the point where the iteration ever exceeds 5
There is 3 pointers here that iterate.
e as the element of string s.
n which is the pointer to the next char of output.
and c which is a copy of n and decrements until it reaches the address of &output[0].
maybe it's something with the memmove or memset since I've never used it before.
I'm completely lost
TL;DR : mixture of char* and std::string are not really good idea if you don't understand how exactly it works.
If you want to length of string you cant do this const unsigned short int size = sizeof(c); (sizeof will return size of pointer (which is commonly 4 on 32-bit machine and 8 on 64-bit machine). You must do this instead: const size_t size = strlen(c);
Address sanitizers is right that you (indirectly) are trying to get an memory which not belongs to you.
How does constructor of string from char* works?
Answer: char* is considered as c-style string, which means that it must be null '\0' terminated.
More details: constructor of string from char* calls strlen-like function which looks like about this:
https://en.cppreference.com/w/cpp/string/byte/strlen
int strlen(char *begin){
int k = 0;
while (*begin != '\0'){
++k;
++begin;
}
return k;
}
If c-style char* string does not contain '\0' it cause accessing memory which doesn't belongs to you.
How to fix?
Answer (two options):
not use mixture of char* and std::string
char* output = new char[s.length()]; replace with char* output = new char[s.length() + 1]; memset(output, 0, s.length() + 1);
Also you must delete all memory which you newed. So add delete[] output; before return res;
I've written this code to replace string in substring (even if previous string was smaller than new). My problem is: crash while RtlMoveMemory()
Here is my function:
char* strreplace(char* s, const char* s1, const char* s2)
{
char* p = strstr(s, s1);
if (p != NULL) {
size_t len1 = lstrlenA(s1);
size_t len2 = lstrlenA(s2);
if (len1 != len2)
{
RtlMoveMemory(p + len2, p + len1, lstrlenA(p + len1) + 1);
}
RtlCopyMemory(p, s2, len2);
}
return s;
}
RtlMoveMemory does not allocate any memory, so your program will crash if the new string is longer than the old string.
Is there any good reason that you are trying to do this with RtlMoveMmeory and RtlCopyMemory instead of standard functions?
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've tried so may ways on the Internet to append a character to a char* but none of them seems to work. Here is one of my incomplete solution:
char* appendCharToCharArray(char * array, char a)
{
char* ret = "";
if (array!="")
{
char * ret = new char[strlen(array) + 1 + 1]; // + 1 char + 1 for null;
strcpy(ret,array);
}
else
{
ret = new char[2];
strcpy(ret,array);
}
ret[strlen(array)] = a; // (1)
ret[strlen(array)+1] = '\0';
return ret;
}
This only works when the passed array is "" (blank inside). Otherwise it doesn't help (and got an error at (1)). Could you guys please help me with this ? Thanks so much in advanced !
Remove those char * ret declarations inside if blocks which hide outer ret. Therefor you have memory leak and on the other hand un-allocated memory for ret.
To compare a c-style string you should use strcmp(array,"") not array!="". Your final code should looks like below:
char* appendCharToCharArray(char* array, char a)
{
size_t len = strlen(array);
char* ret = new char[len+2];
strcpy(ret, array);
ret[len] = a;
ret[len+1] = '\0';
return ret;
}
Note that, you must handle the allocated memory of returned ret somewhere by delete[] it.
Why you don't use std::string? it has .append method to append a character at the end of a string:
std::string str;
str.append('x');
// or
str += x;
The function name does not reflect the semantic of the function. In fact you do not append a character. You create a new character array that contains the original array plus the given character. So if you indeed need a function that appends a character to a character array I would write it the following way
bool AppendCharToCharArray( char *array, size_t n, char c )
{
size_t sz = std::strlen( array );
if ( sz + 1 < n )
{
array[sz] = c;
array[sz + 1] = '\0';
}
return ( sz + 1 < n );
}
If you need a function that will contain a copy of the original array plus the given character then it could look the following way
char * CharArrayPlusChar( const char *array, char c )
{
size_t sz = std::strlen( array );
char *s = new char[sz + 2];
std::strcpy( s, array );
s[sz] = c;
s[sz + 1] = '\0';
return ( s );
}
The specific problem is that you're declaring a new variable instead of assigning to an existing one:
char * ret = new char[strlen(array) + 1 + 1];
^^^^^^ Remove this
and trying to compare string values by comparing pointers:
if (array!="") // Wrong - compares pointer with address of string literal
if (array[0] == 0) // Better - checks for empty string
although there's no need to make that comparison at all; the first branch will do the right thing whether or not the string is empty.
The more general problem is that you're messing around with nasty, error-prone C-style string manipulation in C++. Use std::string and it will manage all the memory allocation for you:
std::string appendCharToString(std::string const & s, char a) {
return s + a;
}
char ch = 't';
char chArray[2];
sprintf(chArray, "%c", ch);
char chOutput[10]="tes";
strcat(chOutput, chArray);
cout<<chOutput;
OUTPUT:
test
in c++ how to search just a part of a string starting from startIndex and ending after some count of chars. in some cases I just need to search the first 5 chars for a special char or string why will I have to come over the whole string it may be 1000 chars or multiples of that. what I know in c++ run time library, all functions don't support something like that for example strchr it will search all of the string, I don't want that I want to compare a specific part of the string from [] to []. I've seen a solution for that problem using wmemchr but I need it to be dependent on the currently selected locale, if anybody know how to do that, I'd be grateful.
Also how to compare just 2 chars directly regarding to the locale?
I'm not aware of a way to do this directly with a standard library, but you could make your own function and strstr pretty easily.
/* Find str1 within str2, limiting str2 to n characters. */
char * strnstr( char * str1, const char * str2, size_t n )
{
char * ret;
char temp = str1[n]; // save our char at n
str2[n] = NULL; // null terminate str2 at n
ret = strstr( str1, str2 ); // call into strstr normally
str2[n] = temp; // restore char so str2 is unmodified
return ret;
}
For your second question:
Also how to compare just 2 chars directly regarding to the locale?
I'm not sure what you mean. Are you asking how to compare two characters directly? If so, you can just compare like any other values.
if( str1[n] == str2[n] ) { ...do something... }
You can use std::substr to limit your search area:
std::string str = load_some_data();
size_t pos = str.substr(5).find('a');
I solved it like that
int64 Compare(CHAR c1, CHAR c2, bool ignoreCase = false)
{
return ignoreCase ? _strnicoll(&c1, &c2, 1) : _strncoll(&c1, &c2, 1);
}
int64 IndexOf(const CHAR* buffer, CHAR c, uint count, bool ignoreCase = false)
{
for (uint i =0; i < count; i++)
{
if (Compare(*(buffer + i), c, ignoreCase) == 0)
{
return i;
}
}
return npos;
}
int64 LastIndexOf(const CHAR* buffer, CHAR c, uint count, bool ignoreCase = false)
{
while(--count >= 0)
{
if (Compare(*(buffer + count), c, ignoreCase) == 0)
{
return count;
}
}
return npos;
}
npos = -1
and to specify the start index pass to (buffer + startIndex) as the buffer to the second or the third method