Why it stops working? Can't we pass the name of the pointer as an argument for strcpy? if I change it to strcpy(&a,&b); it works.
#include <stdio.h>
int main() {
char *a;
a = "aabtyn";
char *b;
b = "mihli";
strcpy(a,b);
printf("%s-%s\n",a,b);
return 0;
}
Can't we pass the name of the pointer as an argument for strcpy?
Yes, we can. However, it is also important that the destination pointer points to a writeable memory; in your case, neither a nor b point to memory that can be written.
if I change it to strcpy(&a,&b); it works.
If it appears to work on your system, it does so by mistake. What you see is undefined behavior. In order for strcpy to work you need to do one of the following:
Allocate a in automatic memory by defining it as char a[] = "aabtyn";, or
Allocate a in dynamic memory by calling char *a = malloc(7); You need seventh byte for null terminator.
According to the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
You declared two pointers to string literals
char *a;
a = "aabtyn";
char *b;
b = "mihli";
Then in this statement
strcpy(a,b);
you are trying to modify the first string literal. So the behaviour of the program is undefined.
As for this statement
strcpy(&a,&b);
then there is an attempt to copy the value of one pointer to another pointer. This call aslo has undefined behaviour. But if the value of the second pointer is zero-terminated then this call can be equivalent to
a = b;
So the first pointer just reassigned. Though in any case there is undefined behaviour.
A valid program can look the following way
#include <stdio.h>
#include <string.h>
int main( void )
{
char s[] = "aabtyn";
char *a = s;
char *b;
b = "mihli";
strcpy(a,b);
printf("%s-%s\n",a,b);
return 0;
}
If you have:
char source[80],dest[80];
Initialize source, then:
strcpy(dest,source);
But if you have:
char *pd,*ps;
Initialize source,and malloc storage for *pd, then:
strcpy(&pd,&ps);
And remember to have free(pd); somewhere before exit(0);
Related
I'm a newbie to C. I had extended the question from the previous question: Strange behavior when returning "string" with C (Thanks for all who answered or commented that question, by the way.)
Pretty straight forward:
Why can this work:
#include <stdio.h>
int func() {
int i = 5;
return i;
}
int main() {
printf("%d",func());
}
But not this:
#include <stdio.h>
char * func() {
char c[] = "Hey there!";
return c;
}
int main() {
printf("%s",func());
}
From the previous question, logically the int i should not exist too because the function has returned, but why can it still be returned while char c[] cannot?
(It seems to be duplicated from "Pointers and memory scope" but I would like to know more about what is the difference between returning an int and a char *.)
Problem is not returning char *, it is returning something that is allocated on stack.
If you allocate memory for your string rather than pointing to function stack, there will be no problem. Something like this:
char * func() {
char c[] = "Hey there!";
return strdup(c);
}
int main() {
char* str = func();
printf("%s", str);
free(str);
}
It is important to mention that in both cases, you are copying a value and in both cases copied value is correct, but the meaning of copied value differs.
In first case, your are copying an int value and after your return from function, you are using that int value which will be valid. But in 2nd case, even though you have a valid pointer value, it refers to an invalid address of memory which is stack of called function.
Based on suggestions in comment, I decided to add another better practice in memory allocating for this code:
#define NULL (void*)0
int func(char *buf, int len) {
char c[] = "Hey there!";
int size = strlen(c) + 1;
if (len >= size) {
strcpy(buf, c);
}
return size;
}
int main() {
int size = func(NULL, 0);
char *buf = calloc(size, sizeof(*buf));
func(buf, size);
printf("%s", buf);
free(buf);
return 0;
}
Similar approach is used in a lot of windows API functions. This approach is better, because owner of pointer is more obvious (main in here).
In the first example the return value is copied. In your second example you're returning a pointer, which will point to a memory location which no longer exists.
In the first case, you return the int value 5 from the function. You can then print that value.
In the second case however, you return a value of type char *. That value points to an array that is local to the function func. After that function returns the array goes out of scope, so the pointer points to invalid memory.
The difference between these two cases is a value that you use directly, versus a pointer value that no longer points to valid memory. Had you returned a pointer to memory allocated by malloc, then the pointer would point to valid memory.
You are trying to return pointer to local array, which is very bad. If you want to return a pointer to array, allocate it dynamically using malloc inside your func();
Then you must call free() on caller side to free up memory you allocated when you no longer need it
In the first example, you return an int, and the second you return a pointer to a char. They both return in exactly the same manner, it is just a matter of understanding the stack and how values are returned.
Even though i was declared in the function and is allocated on the stack, when the function returns it returns the value of i (which is basically copied, so when i falls off the stack the value of i is still returned.)
This is the exact same thing that happens to the char * in the second example. It will still be a pointer to a char, and it returns the 'copied' value of c. However, since it was allocated on the stack, the address it points to is effectively invalid. The pointer value itself has not changed, but what it points to has.
You would have to dynamically allocate this to avoid this situation.
The return value of function is returned by copy. In the first example, you get a copy of the integer variable from the function. In the second you get a copy of the char pointer, not a copy of the string.
The pointer references the string data that has automatic storage, so is no longer valid after the function returns. The space becomes available for use by other code and many be modified - any attempt to access it has undefined behaviour.
The point is, it is a pointer that is returned, not a string; in C a strings (and more generally arrays) are not a first-class data types.
Depending on your needs there are a number of valid ways of returning the string data; for example the following is valid:
char* func()
{
static char c[] = "Hey there!";
return c;
}
because here although the local variable goes out of scope the static data is not destroyed or de-allocated, and any reference to it remains valid.
Another alternative is to embed the string in a struct which is a first-class data type:
typedef struct
{
char content[256] ;
} sString ;
sString func()
{
sString c = {"Hey there!"};
return c;
}
Or more conventionally to copy the data to a caller buffer:
char* func( char* buffer )
{
char c[] = "Hey there!";
strcpy( buffer, c ) ;
return buffer ;
}
I have omitted code to mitigate the possibility of buffer overrun above for clarity in this last example, such code is advised.
I know the C language has dynamic length strings whereby it uses the special character null (represented as 0) to terminate a string - rather than maintaining the length.
I have this simple C code that creates a string with the null character in the fifth index:
#include <stdio.h>
#include <stdlib.h>
int main () {
char * s= "sdfsd\0sfdfsd";
printf("%s",s);
s[5]='3';
printf("%s",s);
return 0;
}
Thus, a print of the string will only output up to the fifth index. Then the code changes the character at the fifth index to a '3'. Given my understanding, I assumed it would print the full string with the 3 instead of the null, as such:
sdfsdsdfsd3sfdfsd
but instead it outputs:
sdfsdsdfsd
Can someone explain this?
This program exhibits undefined behavior because you modify a read-only string literal. char* s = "..." makes s point to constant memory; C++ actually disallows pointing non-const char* to string literals, but in C it's still possible, and we have to be careful (see this SO answer for more details and a C99 standards quote)
Change the assignment line to:
char s[] = "sdfsd\0sfdfsd";
Which creates an array on the stack and copies the string to it, as an initializer. In this case modifying s[5] is valid and you get the result you expect.
String literals can not be changed because the compiler put the string literals into a read-only data-section (but this might vary by underlying platform). The effect of attempting to modify a string literal is undefined.
In your code:
char * s= "sdfsd\0sfdfsd"
Here, s is char pointer pointing to a string "sdfsd\0sfdfsd" stored in read-only memory, making it immutable.
Here you are trying to modify the content of read-only memory:
s[5]='3';
which leads to undefined behavior.
Instead, you can use char[]:
#include <stdio.h>
int main () {
char a[] = "sdfsd\0sfdfsd";
char * s = a;
printf("%s",s);
s[5]='3';
printf("%s\n",s);
return 0;
}
This operation has failed:
s[5] = 3;
You're trying to change a string literal, which is always read-only. My testing shows the program exited with segfault:
Segmentation fault (core dumped)
You should store it in an array (or allocated memory) before any attempts to change it:
char s[] = "sdfsd\0sfdfsd";
With the above change, the program works as intended.
#include <stdio.h>
int main(){
char x[10] = "aa\0a";
x[2] = '1';
puts(x);
printf("\n\n\nPress any key to exit...");
getch();
return 0;
}
Output: aa1a
Code first:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test (char* word)
{
char y[20] = "hlajwoma";
word = &y;
}
int main()
{
char* words[3] = {NULL};
test(words[1]);
words[0] = "LOL0";
words[1] = "LOL1";
words[2] = "LOL2";
printf("%s\n%s\n%s", words[0], words[1], words[2]);
return 0;
}
So what i want to do here, is you can see that i have an array of char* called words. This array stores the memory address of the elements. I choose words[1] to be edited, but it doesn't work.
Can you point me to some directions please?
One problem you have is that arguments are passed by value, basically meaning that they are copied into local variables in the function. Changing a copy will of course not change the original, and also local variables goes out of scope and cease to exist once the function returns. You usually solve it by using pass by reference, which doesn't exist in C but can be emulated with pointers. So you need to pass a pointer to the pointer as the argument, and use dereferencing in the function to change the value.
However that leads us back to the whole "local variable" thing, and how they cease to exist once they go out of scope. Since you want to make the pointer point to the local array y that pointer will no longer be valid once the function returns and using the pointer will lead to undefined behavior.
The actual problem is that you call your function doing the "modification" before you do the assignment. Once you fixed the above problems you should probably change the order you do things.
You are reassigning to words[0] after the function call. So, whatever it's supposed to modify, wouldn't work.
However, your "modification" isn't correct to start with.
With this statement
word = &y;
you are modifying a pointer word that's local to test() function. If you want to modify the content, you can use strcpy(). However, what you pass to test() is an address of a string literal which can't be modified.
In order to modify the pointer, you have to pass a pointer to pointer. But you can't assign the address of a local variable to it (which would lead to undefined behaviour).
What you probably want to do is something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test (char **word)
{
char *y = "hlajwoma";
*word = y;
}
int main(void)
{
char* words[3] = {NULL};
words[0] = "LOL0";
words[1] = "LOL1";
words[2] = "LOL2";
test(&words[0]);
printf("%s\n%s\n%s", words[0], words[1], words[2]);
return 0;
}
This
char *y = "hlajwoma";
assigns the address of the string literal "hlajwoma", which has static storage duration, to y.
This is totally different from:
char y[] = "hlajwoma";
in which the string literal is copied into the array y. Thus array y is local to the function test().
words[1] = "LOL1";
Is a char pointer to a constant string.
If I understand your question correctly, you want your function to be able to modify the array words. In other words, I take that you expect the output to be the following:
LOL0
hlajwoma
LOL
If that's the case, then what you want is your function to receive a pointer to the array, and use this pointer to make the second element point to another string.
However, you'll run into a second problem, which is trying to make the pointer in main point to a string that only exists during the lifetime of test(). That is, when you have a code like this:
void test (char** word)
{
char y[20] = "hlajwoma";
*word = y;
}
The variable y is created by the program in the dynamic memory region when test() is called. When it finishes running, that string no longer exists. And if you stored its address in any pointer, that pointer now is invalid. You can simply make it point to a string literal, which exists during the whole time your program is running.
Another problem with your code is that you are calling test() first and then modifying the array. Even if test() works perfectly, whatever it do is being undone. So we change the order of that as well.
So you can simply do this instead:
#include <stdio.h>
#include <stdlib.h>
void test (char** word)
{
word = "hlajwoma";
}
int main(void)
{
char* words[3] = {NULL};
words[0] = "LOL0";
words[1] = "LOL1";
words[2] = "LOL2";
test(&words[1]);
printf("%s\n%s\n%s", words[0], words[1], words[2]);
return 0;
}
This question already has answers here:
Difference between char[] and char * in C [duplicate]
(3 answers)
Closed 7 years ago.
I think I know the answer to my own question but I would like to have confirmation that I understand this perfectly.
I wrote a function that returns a string. I pass a char* as a parameter, and the function modifies the pointer.
It works fine and here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_file_name(char* file_name_out)
{
char file_name[12+1];
char dir_name[50+12+1];
strcpy(file_name, "name.xml");
strcpy(dir_name, "/home/user/foo/bar/");
strcat(dir_name, file_name);
strcpy(file_name_out, dir_name); // Clarity - equivalent to a return
}
int main()
{
char file_name[100];
get_file_name(file_name);
printf(file_name);
return 0;
}
But if I replace char file_name[100]; by char *filename; or char *filename = "";, I get a segmentation fault in strcpy().
I am not sure why ?
My function takes a char* as a parameter and so does strcpy().
As far as I understand, char *filename = ""; creates a read-only string. strcpy() is then trying to write into a read-only variable, which is not allowed so the error makes sense.
But what happens when I write char *filename; ? My guess is that enough space to fit a pointer to a char is allocated on the stack, so I could write only one single character where my file_name_out points. A call to strcpy() would try to write at least 2, hence the error.
It would explain why the following code compiles and yields the expected output:
void foo(char* a, char* b)
{
*a = *b;
}
int main()
{
char a = 'A', b = 'B';
printf("a = %c, b = %c\n", a, b);
foo(&a, &b);
printf("a = %c, b = %c\n", a, b);
return 0;
}
On the other hand, if I use char file_name[100];, I allocate enough room on the stack for 100 characters, so strcpy() can happily write into file_name_out.
Am I right ?
As far as I understand, char *filename = ""; creates a read-only
string. strcpy() is then trying to write into a read-only variable,
which is not allowed so the error makes sense.
Yes, that's right. It is inherently different from declaring a character array. Initializing a character pointer to a string literal makes it read-only; attempting to change the contents of the string leads to UB.
But what happens when I write char *filename; ? My guess is that
enough space to fit a pointer to a char is allocated on the stack, so
I could write only one single character into my file_name_out
variable.
You allocate enough space to store a pointer to a character, and that's it. You can't write to *filename, not even a single character, because you didn't allocate space to store the contents pointed to by *filename. If you want to change the contents pointed to by filename, first you must initialize it to point to somewhere valid.
I think the issue here is that
char string[100];
allocates memory to string - which you can access using string as pointer
but
char * string;
does not allocate any memory to string so you get a seg fault.
to get memory you could use
string = calloc(100,sizeo(char));
for example, but you would need to remember at the end to free the memory with
free(string);
or you could get a memory leak.
another memory allocation route is with malloc
So in summary
char string[100];
is equivalent to
char * string;
string = calloc(100,sizeo(char));
...
free(string);
although strictly speaking calloc initializes all elements to zero, whereas in the string[100] decalaration the array elements are undefined unless you use
string[100]={}
if you use malloc instead to grad the memory the contents are undefined.
Another point made by #PaulRooney is that char string[100] gives memory allocation on the stack whereas calloc uses the heap. For more information about the heap and stack see this question and answers...
char file_name[100]; creates a contiguous array of 100 chars. In this case file_name is a pointer of type (char*) which points to the first element in the array.
char* file_name; creates a pointer. However, it is not initialized to a particular memory address. Further, this expression does not allocate memory.
char *filename;
Allocate nothing. Its just a pointer pointing to an unspecified location (the value is whatever was in that memory previously). Using this pointer will never work as it probably points outside the memory range your program is allowed to use.
char *filename = "";
Points to a piece of the programs data segment. As you already said it's read only and so attempting to change it leads to the segfault.
In your final example you are dealing with single char values, not strings of char values and your function foo treats them as such. So there is no issue with the length of buffers the char* values point to.
Can I initialize string after declaration?
char *s;
s = "test";
instead of
char *s = "test";
You can, but keep in mind that with that statements you are storing in s a pointer to a read-only string allocated elsewhere. Any attempt to modify it will result in undefined behavior (i.e., on some compilers it may work, but often will just crash). That's why usually you use a const char * for that thing.
Yes, you can.
#include <stdio.h>
int
main(void)
{
// `s' is a pointer to `const char' because `s' may point to a string which
// is in read-only memory.
char const *s;
s = "hello";
puts(s);
return 0;
}
NB: It doesn't work with arrays.
#include <stdio.h>
int
main(void)
{
char s[32];
s = "hello"; // Syntax error.
puts(s);
return 0;
}
It is correct for pointers (as mentioned above) because the string inside quotes is allocated from the compiler at compile time, so you can point to this memory address. The problems comes when you try change its contents or when you have a fixed size array that want to point there