I fell over this little thing while coding:
char* strinit(char* str) {
str = (char*) malloc(100);
strcpy(str, "hello SO");
return str;
}
int main()
{
char* str = strinit(str);
return 0;
}
As you can see, I am using the same variable that I am declaring to initialize it. This is no problem. I tried the same thing in Java. That causes errors.
So my question is: Is there any problems doing this? Can I use it in my code in good conscience?
C & C++ consider that char* str = strinit(str); is legal; because it is evaluated to:
char* str;
str = strinit(str);
see Why is 'int i = i;' legal?
Not everything you can do should be done. The code
char* strinit(char* str) {
str = (char*) malloc(100);
strcpy(str, "hello SO");
return str;
}
uses a parameter only as a local variable. You should change it to
char* strinit(void) {
char* str = malloc(100);
strcpy(str, "hello SO");
return str;
}
and call the function without parameters.
Edit:
There is only a little problem with the actual call of your function. The value of the variable str in the main function is passed to the strinit function. This is cheap in your case. But this can be expensive if the parameter type is a more complex type. The compiler will create a copy of the parameter what can call the objects constructor. Of course, the copy of a pointer is cheap.
Related
I want to change the actual argument passed to a function and not a copy of it. For example:
char str[] = "This is a string";
I want to create a function after a call to which the value of str is different. I tried to create a function accepting char** as the argument but I just couldn't get what I want.
I think you mean something like this:
void update_string(char ** ptr)
{
*ptr = strdup("This is a test");
return;
}
Then call the function like this:
char * str = strdup("hello world\n");
printf("%s\n", str);
update_string(&str);
printf("%s\n", str);
You may pass char*. The pointer will be copied, but it will still point to the same string
If you need the pointer itself to be passed (not its copy) you should pass a char**
To change a string passed to a function in-place, use a regular pointer. For example:
void lower_first_char(char *str)
{
*str = tolower(*str);
}
After this function executes, the first character of the passed string will be changed to lowercase.
Pass a char* if you want to modify the actual string:
foo(str);
...
void foo(char *some_string) {
some_string[0] = 'A';
}
str will now hold "Ahis is a string"
If instead of str being an array, you had: char *str = "Hello";, and wanted to modify where str pointed, then you would pass a char**:
bar(&str);
...
void bar(char **ptr_string) {
*ptr_string = "Bye";
}
str will now point to "Bye".
this is a sample program demonstrating getting a string value from a func
can allocate memory inside called function itself and return
can allocate memory inside calling function and called function just updates it.
i am facing problem with the 2nd way.
is there any workaround?
/*
* main.c
*
* Created on: Sep 6, 2014
* Author: Murtaza
*/
#include<stdio.h>
#include<stdlib.h>
char* someFunc1();
void someFunc2(char* str);
void firstApproach();
void secondApproach();
int main()
{
firstApproach();
printf("\n");
secondApproach();
return 0;
}
char* someFunc1()
{
char *str = (char*)malloc(sizeof(char)*10);
str = "HELLO";
return str;
}
void someFunc2(char* str)
{
str = "Hello";
}
void secondApproach()
{
char *str = (char*)malloc(sizeof(char)*10);
someFunc2(str);
printf(str);
printf("heythere");
}
void firstApproach()
{
char *str;
str=someFunc1();
printf(str);
printf("wassup");
}
Please tell me why the second approach isn't working.
thanks!
my output is:
HELLOwassup
h>heythere
and my expected output should be
HELLOwassup
Helloheythere
void someFunc2(char* str)
{
str="Hello"; //-----the variable str is local to this function, thus it goes out of scope as
// soon as the function returns
}
void secondApproach()
{
char *str=(char*)malloc(sizeof(char)*10);
someFunc2(str);
printf(str); // -------------- here the value inside str is some garbage value.
printf("heythere");
}
CORRECTION :
void someFunc2(char **str )
{
*str = "hello";
}
void secondApproach()
{
char *str=(char*)malloc(sizeof(char)*10);
someFunc2(&str); // pass the address of the string
printf("%s", str);
printf("heythere");
}
Let's take a closer look at someFunc2:
void someFunc2(char* str)
{
/* str is a copy of the pointer that was passed in from secondApproach(). */
str = "Hello";
}
Here, you are passing a pointer by value. Thus, str in someFunc2 is a copy of the original pointer str that was passed in from secondApproach(). someFunc2 tells the copy pointer to point somewhere else, but it leaves the original str pointer alone. The solution is to pass in the address of the str pointer then tell someFunc2 to modify the pointer at that address to point to "hello".
void secondApproach()
{
char* str = (char*) malloc(sizeof(char) * 10);
someFunc2(&str); // Pass in the address of str.
printf("%s", str);
printf("heythere");
}
void someFunc2(char** str)
{
*str = "hello";
}
When you write a string between quotes and use it directly as:
a char* -> it gets created in a mutable place in memory, and gives its address to the pointer variable its assigned to. It is still in memory as long as that variable referencing it is not NULL.
an argument -> it gets created as char* and passed to the function (and treated there as a char*), then automatically disposed from memory (i.e. you can't access it or reference it anymore) ..
So, the only situation when a string is actually mutable is when you assign it to a char[], then it gets created in readonly memory and copied into to the stack .. ( the copy on the stack is what the char[] variable will point to )
If you think about it for some time, you realize that this is one of the benefits of dynamic memory: you can create a char* that is mutable, and since it is just a pointer, you don't need to specify the size of the string it is going to point at. So you can see how useful this would be ..
Also, it's worth to note that in functions:
if you pass a string, the variable in the function itself is treated as a char pointer and most likely would try to modify it, and if it's readonly that would raise a Segmentation Fault. So functions are assuming you know what you're doing ..
if you want a function to be able to modify a string directly (i.e string = "somestring") then pass it a pointer to the actual string, else the modification will only be local to the function. That's because the string is a "pointer to char", so the function can't modify the string as a whole. But that also means that a function can modify the string's characters individually ( obviously, because it has a pointer for characters: the string ). If you pass it, however, a string pointer (char**), the function can modify the string directly (*string = "whatever") and can also modify the characters individually (*string[1] = 'C'). Which choice you need depends entirely on the purpose of the function ..
Now, for your specific example, you can do one of two ..
Using a pointer to a pointer to a char (string pointer)
void someFunc2(char** str)
{
*str = "Hello";
}
Using a pointer to char (string)
void someFunc2(char* str)
{
char *k = "Hello";
for(int i = 0; i < 5; ++i)
str[i] = k[i];
}
This is one of the most controversial and advanced topics in C. No matter what type of C programming you're doing, you have to understand these core concepts ..
I'm starting to learn C and I'm a little bit confuse with c string pointer.
int argc = 0;
const char *str[] = { "hello" , NULL, NULL };
str[argc++] = "nice!";
str[argc++] = "abc";
str[argc++] = "def"
send_args(argc, str);
//the prototype/header : int send_args(int argc, const char **args);
because send_args function doesn't modify the value of passed str, are those operation valid?
because I don't want to do something like :
int i, argc = 0;
char *str[3];
str[argc++] = strdup("nice!");
str[argc++] = strdup("abc");
str[argc++] = strduo("def)"
send_args(argc, str);
for (i = 0; i< argc; i++)
if (str[i]) { free(str[i]); str[i]=NULL; }
Thanks in advance guys.
I see nothing wrong with the first example.
Yes, that's alright. The string literals are likely placed in the initialized data section (details are implementation defined) and there is no need (in fact, not even a possibility) to free literals.
The type of str is compatible with the one required by send_args, so all is fine.
Note that as written, str[] is initialized with three elements and thus cannot hold four or more pointers. You could achieve the same effect with a declaration and initialization like
const char *str[3];
str[0] = "nice!";
str[1] = "abc";
str[2] = "def"
send_args(3, str);
Yes, they are perfectly valid. You need to be concerned about argc though because you are incrementing it one more than needed. It would not cause any "undesirable effects" as far as you are handling it correctly. You can check your code's example here
If you're asking about automatic storage duration, your str array won't be destroyed until execution reaches the end of the block it was created within.
const char **fubar(void)
{
int argc = 0;
const char *str[] = { "hello" , NULL, NULL }; /* str is created here */
str[argc++] = "nice!";
str[argc++] = "abc";
str[argc++] = "def"
send_args(argc, str); /* the lifetime of str is still valid here */
return str; /* ... but str gets destroyed after this "return" statement */
}
int main(void) {
const char **fubared = fubar();
/* str has already been destroyed, and fubar's return value has been rendered garbage */
/* so using fubared would be a bad idea. */
return 0;
}
return causes str to be destroyed, because execution has surpassed the end of the block it was created within, and the pointer being returned would point to garbage.
In this case they are valid, because the strings are stored statically at compile time and cannot be freed. Their pointer addresses also do not depend on the function you are in.
But if you would use a local char array for "nice!", it would not be valid, because the send_args cannot read local variables of other functions.
I want to change the actual argument passed to a function and not a copy of it. For example:
char str[] = "This is a string";
I want to create a function after a call to which the value of str is different. I tried to create a function accepting char** as the argument but I just couldn't get what I want.
I think you mean something like this:
void update_string(char ** ptr)
{
*ptr = strdup("This is a test");
return;
}
Then call the function like this:
char * str = strdup("hello world\n");
printf("%s\n", str);
update_string(&str);
printf("%s\n", str);
You may pass char*. The pointer will be copied, but it will still point to the same string
If you need the pointer itself to be passed (not its copy) you should pass a char**
To change a string passed to a function in-place, use a regular pointer. For example:
void lower_first_char(char *str)
{
*str = tolower(*str);
}
After this function executes, the first character of the passed string will be changed to lowercase.
Pass a char* if you want to modify the actual string:
foo(str);
...
void foo(char *some_string) {
some_string[0] = 'A';
}
str will now hold "Ahis is a string"
If instead of str being an array, you had: char *str = "Hello";, and wanted to modify where str pointed, then you would pass a char**:
bar(&str);
...
void bar(char **ptr_string) {
*ptr_string = "Bye";
}
str will now point to "Bye".
While coding a simple function to remove a particular character from a string, I fell on this strange issue:
void str_remove_chars( char *str, char to_remove)
{
if(str && to_remove)
{
char *ptr = str;
char *cur = str;
while(*ptr != '\0')
{
if(*ptr != to_remove)
{
if(ptr != cur)
{
cur[0] = ptr[0];
}
cur++;
}
ptr++;
}
cur[0] = '\0';
}
}
int main()
{
setbuf(stdout, NULL);
{
char test[] = "string test"; // stack allocation?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // works
printf("After: %s\n",test);
}
{
char *test = "string test"; // non-writable?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // crash!!
printf("After: %s\n",test);
}
return 0;
}
What I don't get is why the second test fails?
To me it looks like the first notation char *ptr = "string"; is equivalent to this one: char ptr[] = "string";.
Isn't it the case?
The two declarations are not the same.
char ptr[] = "string"; declares a char array of size 7 and initializes it with the characters s ,t,r,i,n,g and \0. You are allowed to modify the contents of this array.
char *ptr = "string"; declares ptr as a char pointer and initializes it with address of string literal "string" which is read-only. Modifying a string literal is an undefined behavior. What you saw(seg fault) is one manifestation of the undefined behavior.
Strictly speaking a declaration of char *ptr only guarantees you a pointer to the character type. It is not unusual for the string to form part of the code segment of the compiled application which would be set read-only by some operating systems. The problem lies in the fact that you are making an assumption about the nature of the pre-defined string (that it is writeable) when, in fact, you never explicitly created memory for that string yourself. It is possible that some implementations of compiler and operating system will allow you to do what you've attempted to do.
On the other hand the declaration of char test[], by definition, actually allocates readable-and-writeable memory for the entire array of characters on the stack in this case.
As far as I remember
char ptr[] = "string";
creates a copy of "string" on the stack, so this one is mutable.
The form
char *ptr = "string";
is just backwards compatibility for
const char *ptr = "string";
and you are not allowed (in terms of undefined behavior) to modify it's content.
The compiler may place such strings in a read only section of memory.
char *test = "string test"; is wrong, it should have been const char*. This code compiles just because of backward comptability reasons. The memory pointed by const char* is a read-only memory and whenever you try to write to it, it will invoke undefined behavior. On the other hand char test[] = "string test" creates a writable character array on stack. This like any other regualr local variable to which you can write.
Good answer #codaddict.
Also, a sizeof(ptr) will give different results for the different declarations.
The first one, the array declaration, will return the length of the array including the terminating null character.
The second one, char* ptr = "a long text..."; will return the length of a pointer, usually 4 or 8.
char *str = strdup("test");
str[0] = 'r';
is proper code and creates a mutable string. str is assigned a memory in the heap, the value 'test' filled in it.