I am open to using intermediary C++ code, though C code is the preference.
I have code like the following:
char *fileName1 = "graph";
char *extension1 = ".eps";
I want to create a new char* variable called fileName1WithExtension1 which would correspond to "graph.eps", formed from the two char* variables given above. How can this be done?
If you use C++, have those as std::string strings:
std::string fileName1 = "graph";
std::string extension1 = ".eps";
And then simply
std::string fileName1WithExtension1 = filename1 + extension1;
If you then need to pass that to a C library function expecting a C string, get char pointer with fileName1WithExtension1.c_str()
There really is no reason to muck about with plain C strings in C++ code. It is so error-prone and tedious, that it should be actively avoided.
char *new_string;
new_string = malloc(strlen(fileName1) + strlen(extension1) + 1);
sprintf(new_string, "%s%s", fileName1, extension1);
...
free(new_string)
You can use the asprintf() function
char *buffer;
asprintf (&buffer, "%s%s", fileName1, extension1);
When the buffer variable become useless in your code, you have to free the memory allocated for buffer by asprintf with
free(buffer);
char *joined;
joined = (char*)malloc(strlen(fileName1) + strlen(extension1) + 1);
strcpy(joined, fileName1)
strcat(joined, extension1)
For a small performance increase, if the compiler is smart enough at optimizing, change the last line to
strcpy(joined+strlen(fileName1), extension1)
Even better, store the length of fileName1 in a variable the first time you determine it, and use it in the final strcpy().
If you want to go REALLY low-level, with ugly loops and such, you can do this: (Tested, it compiles and gives the expected and desired results)
char* filename1 = "graph";
char* extension1 = ".eps";
char* filename1WithExtension1 = combine(filename1, extension1);
where:
char* combine(char* str1, char* str2)
{
int str1len = 0, str2len = 0;
while(str1[str1len] != '\0') {
str1len++;
}
while(str2[str2len] != '\0') {
str2len++;
}
int outputlen = str1len + str2len + 1;
char* output = new char[outputlen];
for(int i = 0; i < str1len; i++)
{
output[i] = str1[i];
}
for(int i = str1len; i < outputlen; i++)
{
output[i] = str2[i - str1len];
}
return output;
}
I did a bit of C brush-up for fun, here's an alternative (C90 and C++ compatible code) for joining an array of C strings with separator. It should be very efficient with any decently optimizing compiler, too:
#include <string.h>
#include <stdlib.h>
/* **parts are strings to join, a NULL-terminated array of char*
* sep is separator string, use "" for no separator, must not be NULL
* returns malloc-allocated buffer which must be freed
* if len_out!=NULL, sets *len_out to strlen of result string */
char *astrjoin(int *len_out, const char *sep, char **parts) {
int part_count;
int parts_total_len = 0;
for(part_count = 0; parts[part_count]; ++part_count) {
parts_total_len += strlen(parts[part_count]);
}
if (part_count > 0) {
int malloc_size = (part_count - 1) * strlen(sep) + parts_total_len + 1;
char *result = (char*)malloc(malloc_size);
char *dest = result;
for(;;) {
const char *src;
for(src=*parts; *src; ++src) *dest++ = *src;
if (!*++parts) break;
for(src=sep ; *src; ++src) *dest++ = *src;
}
*dest = 0;
if (len_out) *len_out = malloc_size - 1;
return result;
} else {
if (len_out) *len_out = 0;
return strdup("");
}
}
Example usage:
int main(int argc, char *argv[]) {
/* argv is NULL-terminated array of char pointers */
char *commandline = astrjoin(NULL, " ", argv);
printf("argc: %d\nargv: %s\n", argc, commandline);
free(commandline);
return 0;
}
To call that in context of your question, it could be something like:
char *tmparr[] = { fileName1, exteansion1, NULL };
char *fileName1WithExtension1 = astrjoin(NULL, "", tmparr);
It would be trivial to create a version with sep and/or len_out dropped, or a version supporting "varargs", with signature looking something like:
char *astrjoin_va(int *len_out, const char *sep, ...);
Which would be nicer to call in context of your question:
char *fileName1WithExtension1 = astrjoin_va(NULL, "", fileName1, extension1, NULL);
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;
I am trying to write my own operating system. I have followed the tutorials on the OSDev Wiki, and I am now working on writing a console mode, with commands. I need to be able to split a char* into a char**, without all the library functionality (hence freestanding). I have tried iterating through until I meet my delimiter etc, but however I do it, I just get garbage stuck on the end of my first result. What am I doing wrong? This is what I have so far:
static char** splitStr (char* string, char delim) {
char returner[VGA_WIDTH][255];
int loc = 0;
int innerLoc = 0;
for (int i = 0; string[i] != 0x00; i++) {
char c = string[i];
if (c != delim) {
returner[loc][innerLoc] = c;
innerLoc++;
} else {
print ("a string was ");
println (returner[loc]);
innerLoc = 0;
loc++;
}
}
print ("the first string was ");
println (returner[0]);
return (char**)returner;
}
I am asking a question about how to write a specific function in C++ freestanding mode.
void split(const char* str, const char d, char** into)
{
if(str != NULL && into != NULL)
{
int n = 0;
int c = 0;
for(int i = 0; str[c] != '\0'; i++,c++)
{
into[n][i] = str[c];
if(str[c] == d)
{
into[n][i] = '\0';
i = -1;
++n;
}
}
}
}
I'm allocating using calloc to get rid of garbage characters.
EDIT: You should allocate the pointers inside the char** before writing to them.
void allocarr(char** pointers, int bytes, int slots)
{
int i = 0;
while(i <= slots)
{
pointers[i] = (char*)calloc(1, bytes);
++i;
}
}
...
char** sa = (char**)malloc(50*sizeof(char*));
allocarr(sa, 512, 50);
split("Hello;World;", ';', sa);
puts(sa[0]);
char** strSplit(const char* str, const char splitter)
{
unsigned long splitterCount = strSplitCount(str, splitter) + 1;
char** result = new char*[splitterCount];
unsigned long startRange = 0, endRange = 0;
for (unsigned long i = 0; i < splitterCount; i++)
{
while (str[endRange] == splitter)
{
endRange++;
startRange++;
}
while (str[endRange] != splitter && str[endRange] != '\0')
{
endRange++;
}
result[i] = new char[(endRange - startRange + 1)];
strCopy(result[i], str);
// unsigned long indexOffset = 0;
// for (unsigned long j = startRange; j < endRange; j++)
// {
// if (str[j] != splitter)
// {
// result[i][indexOffset] = str[j];
// }
// indexOffset++;
// }
// result[i][indexOffset] = '\0';
//
// startRange = ++endRange;
}
return result;
}
This function takes in a const char* of a cstring and a const char of where to split within the string. The function correctly splits strings into a char** and returns it. To make the function look cleaner I made a strCopy function which works correctly outside this fucntion. But when strCopy is used within the function visual studio throws a critical error. But to make things even more interesting if you uncomment the commented code and remove the strCopy function the data gets copied correctly and no error is thrown. So why does my strCopy function not work?
void strCopy(char* dest, const char* src)
{
while (*src)
{
*dest = *src;
src++;
dest++;
}
*dest = '\0';
}
Look at this statement
result[i] = new char[(endRange - startRange + 1)];
It is clear that you need to copy str from startRange up to endRange and append the result string with the terminating zero.
However you are trying to copy all the string str.
strCopy(result[i], str);
You need to write a function either like std::strncpy or like std::memcpy and use it to copy substrings.
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;
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?