In my project there is a method which only returns a const char*, whereas I need a char* string, as the API doesn't accept const char*.
Any idea how to convert between const char* to char*?
First of all you should do such things only if it is really necessary - e.g. to use some old-style API with char* arguments which are not modified. If an API function modifies the string which was const originally, then this is unspecified behaviour, very likely crash.
Use cast:
(char*)const_char_ptr
To be safe you don't break stuff (for example when these strings are changed in your code or further up), or crash you program (in case the returned string was literal for example like "hello I'm a literal string" and you start to edit it), make a copy of the returned string.
You could use strdup() for this, but read the small print. Or you can of course create your own version if it's not there on your platform.
You can use the strdup function which has the following prototype
char *strdup(const char *s1);
Example of use:
#include <string.h>
char * my_str = strdup("My string literal!");
char * my_other_str = strdup(some_const_str);
or strcpy/strncpy to your buffer
or rewrite your functions to use const char * as parameter instead of char * where possible so you can preserve the const
A const to a pointer indicates a "read-only" memory location. Whereas the ones without const are a read-write memory areas. So, you "cannot" convert a const(read-only location) to a normal(read-write) location.
The alternate is to copy the data to a different read-write location and pass this pointer to the required function. You may use strdup() to perform this action.
To convert a const char* to char* you could create a function like this :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* unconstchar(const char* s) {
if(!s)
return NULL;
int i;
char* res = NULL;
res = (char*) malloc(strlen(s)+1);
if(!res){
fprintf(stderr, "Memory Allocation Failed! Exiting...\n");
exit(EXIT_FAILURE);
} else{
for (i = 0; s[i] != '\0'; i++) {
res[i] = s[i];
}
res[i] = '\0';
return res;
}
}
int main() {
const char* s = "this is bikash";
char* p = unconstchar(s);
printf("%s",p);
free(p);
}
You can cast it by doing (char *)Identifier_Of_Const_char
But as there is probabbly a reason that the api doesn't accept const cahr *,
you should do this only, if you are sure, the function doesn't try to assign any value in range of your const char* which you casted to a non const one.
For example, you could write this way:
const char* a = "art.bin";
char* b = new char[sizeof(a)];
strcpy(b, a);
Related
I am struggling to write a char* passed as an argument. I want to write some string to char* from the function write_char(). With the below code, I am getting a segmentation fault.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
int main(){
char* test_char;
write_char(test_char);
printf("%s", test_char);
return 0;
}
You have two problems (related to what you try to do, there are other problems as well):
Arguments in C are passed by value, which means that the argument variable (c in your write_char function) is a copy of the value from test_char in the main function. Modifying this copy (like assigning to it) will only change the local variables value and not the original variables value.
Assigning to a variable a second time overwrites the current value in the variable. If you do e.g.
int a;
a = 5;
a = 10;
you would (hopefully) not wonder why the value of a was changed to 10 in the second assignment. That a variable is a pointer doesn't change that semantic.
Now how to solve your problem... The first problem could be easily solved by making the function return a pointer instead. And the second problem could be solved by copying the string into the memory instead of reassigning the pointer.
So my suggestion is that you write the function something like
char *get_string(void)
{
char *ptr = malloc(strlen("some string") + 1); // Allocate memory, +1 for terminator
strcpy(ptr, "some string"); // Copy some data into the allocated memory
return ptr; // Return the pointer
}
This could then be used as
char *test_string = get_string();
printf("My string is %s\n", test_string);
free(test_string); // Remember to free the memory we have allocated
Within the function
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
the parameter c is a local variable of the function. Changing it within the function does not influence on the original argument because it is passed by value. That is the function deals with a copy of the original argument.
You have to pass the argument by reference through pointer to it.
Also the function has a memory leak because at first the pointer was assigned with the address of the allocated memory and then reassigned with the address of the first character of the string literal "some string".
If you want to create a copy of a string literal then what you need is the following
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char( char **s )
{
const char *literal = "some string";
*s = malloc( strlen( literal ) + 1 );
if ( *s ) strcpy( *s, literal );
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
if ( test_char ) puts( test_char );
free( test_char );
}
The program output is
some string
Do not forget to allocate dynamically a character array that is large enough to store also the terminating zero of the string literal.
And you should free the allocated memory when the allocated array is not needed any more.
If you want just to initialize a pointer with the address of a string literal then there is no need to allocate dynamically memory.
You can write
#include <stdio.h>
void write_char( char **s )
{
*s = "some string";
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
puts( test_char );
}
In C, you'll need to pass a pointer to a pointer. Your malloc call is trying to change the value of the variable that's being passed in, but it's actually only a copy. The real variable you pass in will not be changed.
Also, the way that you copy a string into a char* is not using assignment... Here's some revised code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void write_char(char** c){
size_t len = strlen("some string");
*c = (char*)malloc(len + 1); // + 1 for null termination
strncpy(*c, "some string", len);
}
int main(){
char* test_char;
write_char(&test_char);
printf("%s", test_char);
return 0;
}
String assignment in C is very different from most modern languages. If you declare a char * and assign a string in the same statement, e.g.,
char *c = "some string";
that works fine, as the compiler can decide how much memory to allocate for that string. After that, though, you mostly shouldn't change the value of the string with =, as this use is mostly for a constant string. If you want to make that especially clear, declare it with const. You'll need to use strcpy. Even then, you'll want to stay away from declaring most strings with a set string, like I have above, if you're planning on changing it. Here is an example of this:
char *c;
c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
If you're passing a pointer to a function that will reallocate it, or even malloc in the first place, you'll need a pointer to a pointer, otherwise the string in main will not get changed.
void myfunc(char **c) {
char *tmp = realloc(*c, 32 * sizeof(char));
if(tmp != NULL) {
*c = tmp;
}
}
char *c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
myfunc(&c);
char* test_char="string"; // initialize string at the time of declaration
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
}
int main(){
char* test_char="strin";
write_char(test_char);
printf("%s", test_char);
return 0;
}
I am trying to compare szFileName1 and szFileName2 , if they are not same, then I am renaming it, but when I am trying to concatenate using snprintf it's giving segmentation fault.what mistake am I doing here?
typedef struct{
char filePath[100];
} filectx;
void filename1(filectx *ctx, const char ** szFileName1){
*szFileName1 = ctx->filepath;
}
void filename2(const char ** szFileName2){
char buf[20] = "/usr/bin/abb.txt";
snprintf(szFileName2, sizeof(szFileName2), "%s%s", szFileName2, buf);
}
int main(){
const char* szFileName1 = NULL;
const char *szFileName2 = malloc(100);
filectx ctx;
ctx.filePath = "/usr/bin/abc.txt";
filename1(&ctx, &szFileName1);
filename2(&szFileName2);
if(strcmp(szFileName1, szFileName2) != 0){
const char szFilePath1[200] = "/local/";
const char szFilePath2[200] = "/local/";
snprintf(szFilePath1, sizeof(szFilePath1), "%s%s", szFilePath1, szFileName1);
snprintf(szFilePath2, sizeof(szFilePath2), "%s%s", szFilePath2, szFileName2);
int ret = rename(szFilePath1, szFilePath2);
}
free(szFileName2);
return 0;
}
I think the problem here is with the arguments you pass to snprintf().
snprintf() expects an argument of type string ("char *"), but not "char **".
Here you are passing a pointer instead of the actual string. So when it tries to access the address it gives segmentation fault.
Change the parameters in the functions filename1() and filename2() to "char *" type and see. It should work.
Hope this helps.
Kranthi
With
const char szFilePath1[200] = "/local/";
const char szFilePath2[200] = "/local/";
as well as others as your function arguments, you declare those variables const. You then try to write to them with snprintf. Don't make these const.
You also can't reuse a variable as source and destination in snprintf.
I'm surprised that the compiler allowed you to compile this.
Although snprintf() doesn't work in your case, why don't you use strcat() or strncat()?
Instead of
snprintf(szFilePath1, sizeof(szFilePath1), "%s%s", szFilePath1, szFileName1);
you can write
strncat(szFilePath1, szFileName1, strlen(szFilePath1));
And by the way:
WHY did you write
sizeof(szFilePath1)
?
So, points to improve
In the very beginning:
*szFileName1 = ctx->filepath;
Not a nice thing to do. It's better to use strcpy()/strncpy(). And passing char ** argument also looks pretty strange.
Stated above. Usage of snprintf's
I'm acquainting myself with c-strings and pointers by using a very simple program.
This version, which passes in a string by reference, works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char **string) {
*string = (char *)malloc(5);
char *temp = "hell";
strcpy(*string, temp);
}
int main(int argc, char *argv[]) {
char *string = NULL;
test(&string);
printf("%s\n", string);
return 0;
}
It prints "hell".
This version, which simply passes the string by value, does not work, and results in a SEGFAULT:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char *string) {
string = (char *)malloc(5);
char *temp = "hell";
strcpy(string, temp);
}
int main(int argc, char *argv[]) {
char *string = NULL;
test(string);
printf("%s\n", string);
return 0;
}
From what I know, the first version makes sense because I pass in the address of the address of the string. Thus, when I dereference this double pointer, I get the real address of the string and can reassign it with malloc.
The second version, however, I'm kind of unclear why it doesn't work. In this version I pass the address of string into the test function. I read that everything in C is passed by value but that array names are actually addresses. Doesn't this mean that I'm passing in the actual address of string into test? Shouldn't things work out the same? I'm confused, please help me out.
Remember This : In C programming to use a value,you pass "by value". To change a value you must pass "by address". So,if what you want to change is an address,then you need to pass its address to change it.otherwise you may only use it.
When you pass an argument "by value", the value of the argument is copied into the formal argument in the function. Changing a copy (in your case string inside the test function) will of course not change the original (string in the main function).
On a side-note, C doesn't actually have "pass by reference", it only have pass by value. You emulate pass by reference by using pointers.
In your second version, string itself is being passed by value, so you simply cannot change string itself. This is for the similar reason you cannot change the value of an int or float when it is passed by value. While an argument is being passed by value, there is a local copy created in the called function's stack.
You can always change the content of string, however.
In C, array type is represented as a pointer to its first element. * in type means "pointer to", but outside of type means "dereference pointer". When you pass argument to function, in the body of function, you have copy of the thing, that you passed. Lets analyse your code with that in mind:
void test(char **string) { //expect pointer to string
*string = (char *)malloc(5); //dereference pointer to string and allocate memory (*string is of type char*, it is a string)
char *temp = "hell"; //create new string
strcpy(*string, temp); //copy new string to the old one
}
int main(int argc, char *argv[]) {
char *string = NULL; //create empty pointer (string is array, which is pointer to char), but NULL is not a valid string
test(&string); //pass pointer to string
printf("%s\n", string); //print string
return 0;
}
**sting did not change, but its contents *string did.
And in the second one:
void test(char *string) { //with this type, you could modify, what is actual string content (for example first letter), but you pass here NULL, so there is nothing you can do
string = (char *)malloc(5); //here, you are changing only COPY of the pointer, that you passed in main
char *temp = "hell"; //create another string
strcpy(string, temp); //copy new string to the one created, after this operation pointer to the string is lost
}
int main(int argc, char *argv[]) {
char *string = NULL; //the same
test(string); //pass the string, you are screwed here, values in C are passed by copying, so even if you modify the string correctly, you will not see the result
printf("%s\n", string); //the string variable never changed from NULL, so you get the error
return 0;
}
I'm getting a core dump that I have no clue how to solve. I have searched other questions and googled my problem but I just can't figure out how to solve this...
Here is the code:
const char checkExtension(const char *filename)
{
const char *point = filename;
const char *newName = malloc(sizeof(filename-5));
if((point = strrchr(filename,'.palz')) != NULL )
{
if(strstr(point,".palz") == 0)
{
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
return point;
}
The function was called char checkExtensions(const char *filename). I added the const due the solutions that I have found online but so far I haven't been able to make it work...
Thank you in advance for the help!
You have many problems with your code. Here are some of them:
Your function returns char which is a single character. You need to return a pointer to an array of characters, a C string.
You don't allocate the right amount of memory. You use sizeof() on a pointer which yields the size of a pointer.
You make it impossible for the caller to know whether or not to deallocate memory. Sometimes you heap allocate, sometimes not. Your approach will leak.
You pass '.palz', which is a character literal, to strrchr which expects a single char. What you mean to pass is '.'.
A better approach is to let the caller allocate the memory. Here is a complete program that shows how:
#include <string.h>
#include <stdio.h>
void GetNewFileName(const char *fileName, char *newFileName)
{
const char *dot = strrchr(fileName, '.');
if (dot)
{
if (strcmp(dot, ".palz") == 0)
{
size_t len = dot - fileName;
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
}
size_t len = strlen(fileName);
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
int main(void)
{
char fileName[256];
char newFileName[256];
strcpy(fileName, "foo.bar");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz.txt");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
return 0;
}
Output
foo.bar foo.bar
foo.bar.palz foo.bar
foo.bar.palz.txt foo.bar.palz.txt
Note that strcmp compares sensitive to letter case. On Windows file names are insensitive to case. I will leave that issue for you to deal with.
By letting the caller allocate memory you allow them to chose where the memory is allocated. They can use a local stack allocated buffer if they like. And it's easy for the caller to allocate the memory because the new file name is never longer than the original file name.
This is most probably your problem:
const char *newName = malloc(sizeof(filename-5));
First, filename is of type const char *, which means that (filename - 5) is also of this type. Thus, sizeof(filename - 5) will always return the size of the pointer datatype of your architecture (4 for x32, 8 for x64).
So, depending on your architecture, you are calling either malloc(4) or malloc(8).
The rest of the code doesn't even compile and it has serious string manipulation issues, so it's hard to tell what you were aiming at. I suppose the strncpy() was copying too much data into newName buffer, which caused buffer overflow.
If your goal was to extract the filename from a path, then you should probably just use char *basename(char *path) for that.
Several pretty major problems with your code. Making it up as I type, so it may not fix everything first time right away. Bear with me.
You need to return a char *, not a char.
const char checkExtension(const char *filename)
{
const char *point = filename;
You malloc memory but the instruction flow does not guarantee it will be freed or returned.
sizeof(filename) should be strlen(filename), minus 5 (sans extension) but +1 (with terminating 0).
const char *newName = malloc(sizeof(filename-5));
strrchr searches for a single character. Some compilers allow "multibyte character constants", but they expect something like 2 -- not five. Since you know the length and start of the string, use strcmp. (First ensure there are at least 5 characters. If not, no use in testing anyway.)
if((point = strrchr(filename,'.palz')) != NULL ) {
Uh, strstr searches for a string inside a string and returns 0 if not found (actually NULL). This contradicts your earlier test. Remove it.
if(strstr(point,".palz") == 0)
{
strncpy copies n characters, but famously (and documented) does not add the terminating 0 if it did not get copied. You will have to this yourself.
.. This is actually where the malloc line should appear, right before using and returning it.
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
You return the original string here. How do you know you need to free it, then? If you overwrote a previous char * its memory will be lost. Better to return a duplicate of the original string (so it can always be freed), or, as I'd prefer, return NULL to indicate "no further action needed" to the calling routine.
return point;
}
Hope I did not forget anything.
There are several problems with your code:
Wrong return type:
const char checkExtension(const char *filename){
You need to return a pointer (const char *), not a single character.
Not enough memory:
const char checkExtension(const char *filename){
const char *newName = malloc(sizeof(filename-5));
You are allocating the size of a pointer (char *), which is typically 4 or 8. You need to call strlen() to find out the size of the string:
Multibyte character:
if((point = strrchr(filename,'.palz')) != NULL ) {
'.palz' is a multibyte character literal. While this is allowed in C, its value is implementation-defined and might not do what you expect. String literals use double quotes (".palz").
No terminating zero:
strncpy(newName, filename, strlen(filename)-5);
Note that strncpy() doesn't necessarily null-terminate the target string. It write at most strlen(filename)-5 characters. If the source string contains more characters (as in your case), it will not write a terminating zero.
I'm not sure what exactly you're trying to do. Perhaps something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char *checkExtension(const char *filename)
{
int len = strlen (filename)-5;
char *newName = NULL; /* return NULL on allocation failure. */
if (len > 0 && !strcmp (filename+len, ".palz")) {
newName = malloc (len+1);
if (newName) {
memcpy (newName, filename, len);
newName[len] = 0;
}
}
return newName;
}
int main (int ac, char **av)
{
if (ac > 1) {
const char *p = checkExtension (av[1]);
puts (p ? p : "NULL");
} else {
puts ("?");
}
return 0;
}
Multiple errors here. You have not said what you are trying to achieve, that has to be implied from the code. You have declared point and newName as const, yet reassigned with a value. You have tested strstr() == 0 when it should be strstr() == NULL. You have called strrchr(filename,'.palz') but sent a string instead of a char. Then you have returned the local variable point which goes out of scope before you get a chance to use it, because it was not declared as static. So it's irrelevant whether you returned a char or a char pointer.
char *checkExtension(const char *filename) {
// if filename has extension .palz return a pointer to
// the filename stripped of extension or return NULL
char *point;
static char newName[512];
strncpy(newName, filename, 512);
if ((point = strstr(newName, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
// printf("%s\n",newName ); // use only for debugging
return newName;
}
}
return NULL;
}
Alternatively provide a string the function can modify -
char *checkExtension(const char *filename, char *newName) { ... }
Alternatively provide a filename the function can modify -
char *checkExtension(char *filename) {
char *point;
if ((point = strstr(filename, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
return filename;
}
}
return NULL;
}
I'm new to C and trying to split a character array (which I receive from a Serial Port in Ardunio). I looked up some tutorials and came up with this. Help me debug it please.
char action[10];
unsigned long duration;
void split(char input[20])
{
char *param, *ptr;
param = strtok_r(input, "#", &ptr);
action = *param; // Need help with this line
param = strtok_r(NULL, "!", &ptr);
duration = (unsigned long) *param; // Need help with this line
}
From what I understand, strtok_r returns a pointer to the character right after the delimiter(#). So if I wanted action[] to be a subset character array of input[] till the delimiter, what should I do?
Edit:
Input is something like this: "left#1000!"
It looks like your first token is a string, and the second token is a long. You can use strncpy to copy param into action, and then strtoul to parse an unsigned long to duration.
param = strtok_r(input, "#!", &ptr);
strncpy(action, param, sizeof(action));
// Force zero termination
action[sizeof(action)-1] = '\0';
param = strtok_r(NULL, "#!", ptr);
duration = strtoul(param, ¶m, 10);
You cannot initialize action = *param.
You need to use
memcpy(action, param, strlen(param))
and
duration = (unsigned long) atoi(param)
This snippet should work in plain C (comments added). You could use a C struct to collect values. Structs may be returned from functions like simple data types (as is shown). You could use that as a start for your own program.
Edit: Such programs don't need the strXYZ(..) functions (useful if you may have '\0'-bytes in your incoming data).
...
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct {
char action[10]; unsigned long duration;
} Result;
Result split(char *input, char delim)
{
Result result = {'\0', 0}; // initialize result by zeros
char *p = (char*)memchr(input, delim, sizeof(result.action)-1);
if(p != NULL) { // if delimiter found in input
memcpy(result.action, input, p-input); // copy text till delimiter
result.duration = strtoul(p+1, NULL, 10); // convert number after delimiter
}
return result; // return values
}
int main(char argc, const char*argv[])
{
char input[20] = "left#1000!";
Result result = split(input, '#');
printf("action: %s, duration %u\n", result.action, result.duration);
return 0;
}
...
Regards
rbo
You should use strcpy() and necessary casting in order to assign strings(or char arrays) in C.
Visit http://en.cppreference.com/w/c/string/byte/strcpy
This function will care for membervise assignment between strings. To do it manually you must use loops and assign each array member seperately.