How would I manually concatenate two char arrays without using the strncpy function?
Can I just say char1 + char2?
Or would I have to write a for loop to get individual elements and add them like this:
addchar[0] = char1[0];
addchar[1] = char1[1];
etc
etc
addchar[n] = char2[0];
addchar[n+1] = char2[1];
etc
etc
To clarify, if
char1 = "happy"
char2 = "birthday"
I want addchar to = happybirthday
For a C-only solution use strncat:
char destination[80] = "";
char string1[] = "Hello";
char string2[] = " World!";
/* Copy string1 to destination */
strncat(destination, string1, sizeof(destination));
/* Append string2 to destination */
strncat(destination, string2, sizeof(destination) - sizeof(string1));
Note that the strn* family of string functions are safer than the ones without n, because they avoid the possibility of buffer overruns.
For a C++ solution, simply use std::string and operator+ or operator+=:
std::string destination("Hello ");
destination += "World";
destination += '!';
If you consider two trivial loops to be "manual", then yes, without using the standard library this is the only way.
char *append(const char *a, const char *b) {
int i = 0;
size_t na = strlen(a);
size_t nb = strlen(b);
char *r = (char*)calloc(na + nb + 1, 1);
for (i = 0; i < na; i++) {
r[i] = a[i];
}
for (i = 0; i < nb; i++) {
r[na + i] = b[i];
}
return r;
}
Remember to call free.
If you're using c++ just use an std::string. With std::strings, the + operator is supported, so you can do string1+string2.
Without using library functions, here is the procedure:
1. Point to the first character in string1.
2. While the current character at the pointer is not null, increment the pointer.
3. Create a "source" pointer pointing to string2.
4. While the character at the "source" location is not null:
4.1. Copy the character from the "source" location to the location pointed to by the String1 pointer.
4.2. Increment both pointers.
Unless this is homework, use C++ std::string for your text.
If you must use C style strings, use the library functions.
Library functions are optimized and validated, reducing your development time.
Alright, you want something like this:
char1 + char2
First, let's see the insane solution:
C:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length_left = strlen(a_Left);
unsigned int length_right = strlen(a_Right);
unsigned int length = length_left + length_right;
char* result = (char*)malloc(length);
// clear the string
memset(result, 0, length);
// copy the left part to the final string
memcpy(result, a_Left, length_left);
// append the right part the to the final string
memcpy(&result[length_left], a_Right, length_right);
// make sure the string actually ends
result[length] = 0;
return result;
}
C++:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length_left = strlen(a_Left);
unsigned int length_right = strlen(a_Right);
unsigned int length = length_left + length_right;
char* result = new char[length];
// clear the string
memset(result, 0, length);
// copy the left part to the final string
memcpy(result, a_Left, length_left);
// append the right part the to the final string
memcpy(&result[length_left], a_Right, length_right);
// make sure the string actually ends
result[length] = 0;
return result;
}
Now, let's see the sane solution:
char* StringAdd(char* a_Left, char* a_Right)
{
unsigned int length = strlen(a_Left) + strlen(a_Right);
char* result = new char[length];
strcpy(result, a_Left);
strcat(result, a_Right);
return result;
}
So, was this homework? I don't really care.
If it was, ask yourself: what did you learn?
Related
At first, I would like to point out that despite using C ++ I cannot use strings or vectors. It is like C with objects.
Ok I have class A with char* test() method:
char* A::test()
{
char to_return[3*this->some_value+3];
for (int i = 0; i < this->some_value; i++)
{
to_return[3*i] = '♥';
to_return[3*i+1] = 'b';
to_return[3*i+2] = ' ';
}
char* dto_return = to_return;
return std::move(dto_return);
}
next in object of class B I have:
ofstream file;
file.open("myfile.txt", ofstream::out | ofstream::trunc);
file.close();
file.open("myfile.txt");
char* to_write = a_obj->test();
size_t len = strlen(to_write);
file.write((char*)&len, sizeof(len));
file.write(to_write, len);
file.close();
(based on this answer)
but the content of the file is:
¥b ¥b ¥b m
and it is definitely not what I'm looking for. The content should be:
♥b ♥b ♥b
How to fix that?
The problems are:
to_return is a local array that ends its lifetime on returning from the function, so returning its pointer is a bad idea.
'♥' may differ from what you want, especially when ♥ cannot be represented by one byte in your character code.
To overcome this problems:
Allocate a dynamic array that persists after returning from the function.
Use string literal to represent the characters to add.
char* A::test()
{
const char *part = "♥b ";
size_t part_len = strlen(part);
char *to_return = new char[part_len*this->some_value+1];
for (int i = 0; i < this->some_value; i++)
{
strcpy(to_return + part_len * i, part);
}
return to_return;
}
The dynamic array returned should be freed via delete[] after completed to use.
char* to_write = a_obj->test();
// ...
delete[] to_write;
Assuming you read the title, here's a little example in pseudo code:
char inputChar[5][20];
{put data in array obviously}
char * outputChar;
copy(inputChar[2][7], inputChar[2][18], outputChar);
printf("%s", outputChar);
or optionally (although I prefer the above version):
char inputChar[5][20];
{put data in array obviously}
std::string outputString;
copy(inputChar[2][7], inputChar[2][18], outputString);
cout outputString; //I don't know how to use std::strings with printf
I've tried std::copy and memcpy but I can't get it to work. The result either gives me random characters that aren't part of the string, or just results in compiler errors due to me not understanding the syntax fully.
EDIT:
Here is the actual code I'm using:
(assume for this example that storeMenu already has data assigned to it)
int line = 0
int frame5 = 11;
char storeMenu[9][13];
char * temp1 = new char[12];
char * temp2 = new char[12];
std::copy(&storeMenu[line+1][0], &storeMenu[line+1][frame5-10], temp1);
std::copy(&storeMenu[line][frame5-10], &storeMenu[line][12], temp2);
To use std::copy you need a pointer to the location of the character, you are passing the character itself here. You also need to initialize outputChar.
char inputChar[5][20] = {"abc","def","ghi01234567890","jkl"};
char * outputChar = new char[20];
auto last = copy(&inputChar[2][0], &inputChar[2][5], outputChar);
*last = '\0';
printf("%s\n", outputChar);
Alternatively using std::string:
char inputChar[5][20] = {"abc","def","ghi01234567890","jkl"};
string outputChar;
copy(&inputChar[2][0], &inputChar[2][5], back_inserter(outputChar));
printf("%s\n", outputChar.c_str());
Using inputs as std::string too:
string inputChar[5] = {"abc","def","ghi01234567890","jkl"};
int fromChar = 2; // from (inclusive) ^ ^
int toChar = 5; // to (exclusive) ^
string outputChar;
copy(inputChar[2].begin()+fromChar, inputChar[2].begin()+toChar, back_inserter(outputChar));
printf("%s\n", outputChar.c_str());
cout << outputChar << endl;
I'm doing an exercise in which I have to copy a c-style string into memory allocated on free store. I am required to do it without using subscripting and relying solely on pointer arithmetic. I wrote the following function-
char* str_dup(const char* s)
{
// count no. of elements
int i = 0;
const char* q = s;
while (*q) { ++i; ++q; }
//create an array +1 for terminating 0
char* scpy = new char[i + 1];
//copy elements to new array
while (*s)
{
*scpy = *s;
++s;
++scpy;
}
*scpy = 0;
return scpy;
}
The function is returning random characters. But if I change it into this-
char* str_dup(const char* s)
{
// count no. of elements
int i = 0;
const char* q = s;
while (*q) { ++i; ++q; }
//create an array +1 for terminating 0
char* scpyx = new char[i + 1];
char* scpy = scpyx;
//copy elements to new array
while (*s)
{
*scpy = *s;
++s;
++scpy;
}
*scpy = 0;
return scpyx;
}
it works. Can someone explain me why first code is not working and second is working?
The first code is not working since you return the final value of scpy, which at that point points at the terminating NUL character, and not the start of the string.
One solution is to do as you did, and save a copy of the original pointer to have something to return.
You should really use strlen() and memcpy(), they make this easier but perhaps they're off-limits to you.
I have a problem with memory access. When i = 0, Visual Studio throws an exception with reference to a line as labelled in the following code.
Can't access at 0x00AD8B3B and 0x00AD8B3B equals scr+np-i
How can I fix the for-loop body so as to fix this issue?
int o_strrev(char* scr)
{
int np = strlen(scr) - 1;
char tmp;
if (!scr) return -1;
if (!*scr) return -1;
for (int i = 0; i < np / 2; i++)
{
tmp = scr[np-i];
scr[np-i] = scr[i]; # this line
scr[i] = tmp;
}
return 0;
}
As pointed out by #Revolver_Ocelot, you are probably passing a const char* from a string literal. Since these are, by definition, constant, you can't modify them in the way you're trying to. You need some way to convert const char* into a non constant char*. Something along these lines will work for you:
string str = "string";
char* cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
I've compiled your code in g++ using non constant char* and it works fine. Just remember to deallocate your char* when you're done with it. We don't want memory leaks ;)
I see you are trying to reverse a string.
Might I suggest a simpler way
void reverse(char *string_var)
{
int length, c;
char *begin, *end, temp;
length = strlen(string_var);
begin = string_var;
end = string_var;
for (c = 0; c < length - 1; c++)
end++;
for (c = 0; c < length/2; c++)
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
Make sure you pass character array of the form
char word[64]
Or maybe by recursion
void reverse(char *x, int begin, int end)
{
char c;
if (begin >= end)
return;
c = *(x+begin);
*(x+begin) = *(x+end);
*(x+end) = c;
reverse(x, ++begin, --end);
}
You're most likely calling o_strrev with a string literal, some thing like:
o_strrev("This ain't gonna work!");
This will compile with most compilers and at most generate a warning. Try cranking up your warning level.
Instead, you want to make a dynamic copy of your string on the heap and work with a char* pointer to that, something like:
string str = "This is gonna work!!"
size_t len = str.size();
char* my_string = new char[len + 1];
strncpy(my_string, str.data(), len)
my_string[len] = '\0';
o_strrev(my_string);
// ...
delete[] my_string;
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