change a string in a function passing a pointer - c

Hello I have some trouble with pointer !
#include <stdio.h>
#include <stdlib.h>
void test(char **str)
{
*str = (char *)malloc(sizeof(char) * 2);
*str[0] = 'b';
*str[1] = '\0';
}
int main(void)
{
char *str;
test(&str);
printf("%s\n", str);
return (0);
}
So I pass a pointer of an non allocated string in my function test, then I allocate my string in the function and try to manipulate it but this code segfault so I guess I miss something on my pointer lesson :)
Can you help me to figure out what is happening here ? thank you a lot !
edit : when I remove my return (0) in the main, the code compile and display my char * ! super weird

The array subscript operator [] has higher precedence than the indirection operator *. So the assignment to str is effectively this which is incorrect:
*(str[0]) = 'b';
*(str[1]) = '\0';
You need to add parenthesis:
(*str)[0] = 'b';
(*str)[1] = '\0';

You must write:
(*str)[0]= 'b';
You must first dereference the str and now the indexing will work on the target, the memory allocated by malloc.

Actually, just 'str' itself means he address of character array.
But 'str' means the value of str.
So the str[0] contains the value of 'b' but as you added '' before str[0] (*str[0]), computer trying to find the value where the address is 'b'.
But this address is not allowed for this process. So this program returns segment fault. Thank you.

Related

Dereferencing pointers confusion

I'm trying to learn about pointers in the C language. But I have a question regarding dereferencing them.
This piece of code works fine, it displays 'i' as I desire.
Code-1
#include <stdio.h>
void myfunction(char** str);
int main()
{
char *name = "Gianni";
myfuntion(&name);
return 0;
}
void myfunction(char** str){
char* test = *str;
printf("%c", test[1]);
}
But what I guessed to have the same result turns out to be a little bit different. My question is why do I not get the same result from the second piece of code?
I dereferenced the pointer so it points to the first character again and can read it until the '\0' terminator. So I thought it would be possible to display the single characters here as well.
Code-2
#include <stdio.h>
void myfunction(char** str);
int main()
{
char *name = "Gianni";
myfuntion(&name);
return 0;
}
void myfunction(char** str){
printf("%c", *str[1]);
}
This is precedence issue.(Array subscript [] has higher precedence than dereference *). You should try
(*str)[1]
This will give you the correct result. In earlier case (In Code-2) you had undefined behavior. You were de-referencing str[1] which is pointing to out of bound memory.
So initially what you were doing in Code-2
*str[1] --> *(*(str+1))
Now what we did,
(*str)[1] --> *((*str)+1)
Well in the modification you are basically getting the address of the array (string literals are array which decayed into pointer) and then you index into correct position - which will give you the correct result.
Well if you check earlier example you will see the similarity. Earlier code (Code-1) you print temp[1] which is *(temp+1) But what is temp? In the line before you did this temp = *str so what is it you are doing?
*(temp+1) --> *(*str+1) --> *((*str)+1)

String pointers in c language

Can any one tell me why the following program crashes.
#include<stdio.h>
#include<string.h>
int main()
{
char **str;
strcpy(*str, "One");
puts(*str);
}
And why the following program doesn't.
#include<stdio.h>
#include<string.h>
int main()
{
char **str;
*str = "One";
puts(*str);
}
strcopy assumes you have memory available.
In the second one you are pointing *str at the statically allocated "One" char[] literal which decays to a pointer. This is actually undefined as well, since str isn't init'd you're still copying a pointer to gibberish.
In the first one you're trying to copy a string to wherever *str points to when left uninitialized. This will almost certainly crash your program since it's just pointing to some garbage address.
So to do this correctly
//allocate space for ARRAY_SIZE pointers
char **str = malloc(sizeof(char*) * ARRAY_SIZE);
*str = "One"; // assign the address of "One"
puts(*str); // print it.
...
free(str);
The first one:
str decleared as char**, But you did not use memorey allocation for that!
Remmber, str is pointer to pointer, so if you want to keep an adress in str*, you should use memorey allocation or initialize in the declaration row!!
In your code, str* is just an adress, not a string!
The second one is about the same idea.
Your second one doesn't crash due to sheer luck. It ought to be like this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char **str = malloc(sizeof *str);
if ( str != NULL ) {
*str = "One";
puts(*str);
free(str);
}
return 0;
}
or:
#include<stdio.h>
#include<string.h>
int main()
{
char * str;
str = "One";
puts(str);
return 0;
}
As you wrote it, you're trying to stuff the address of the string literal "One" into unallocated memory, which gives you undefined behavior.
Your first one crashes for the same reason, you're trying to copy the bytes 'O', 'n', 'e', and '\0' into unallocated memory.
In the first program, you are doing a string copy to a non memory allocated pointer. (*str) has no malloc, new, etc..
In the second one, you are pointing the string pointer to a stack variable. the str pointer will only be valid during the context of the call and when the function exits the str pointer will point to an invalid space. Since this is main(), you don't see that

pointer, malloc and char in C

im trying to copy a const char array to some place in the memory and point to it .
lets say im defining this var under the main prog :
char *p = NULL;
and sending it to a function with a string :
myFunc(&p, "Hello");
now i want that at the end of this function the pointer will point to the letter H but if i puts() it, it will print Hello .
here is what i tried to do :
void myFunc(char** ptr , const char strng[] ) {
*ptr=(char *) malloc(sizeof(strng));
char * tmp=*ptr;
int i=0;
while (1) {
*ptr[i]=strng[i];
if (strng[i]=='\0') break;
i++;
}
*ptr=tmp;
}
i know its a rubbish now, but i would like to understand how to do it right, my idea was to allocate the needed memory, copy a char and move forward with the pointer, etc..
also i tried to make the ptr argument byreferenec (like &ptr) but with no success due to a problem with the lvalue and rvalue .
the only thing is changeable for me is the function, and i would like not to use strings, but chars as this is and exercise .
thanks for any help in advance.
Just replace all the char* with std::string. Do that until you have a very specific reason to not use existing utilities, which is something you don't have as a beginner. None of the code above requires malloc() or raw pointers.
Some more notes:
const char strng[] as parameter is the same as const char* strng. The array syntax doesn't make it an array, it remains a pointer. I don't use this syntax in order to avoid this confusion.
Use static_cast or one of the other C++ casts not the C-style like (char*)malloc(..). The reason is that they are safer.
Check the return value of malloc(), it can return null. Also, you must call free() eventually, otherwise your application leaks memory.
Finally, the pointer does point to the 'H', which is just the first element of the string. Output *p instead of p to see this.
You code work as desired except
*ptr[i]=strng[i];
should be
(*ptr)[i]=strng[i];
Without the parens, it acts like `*(ptr[i])=strng[i];
2) Also
malloc(sizeof(strng));
s/b
malloc(strlen(strng)+1);
You may want to look at strdup(strng).
[edit per OP's request]
difference between *(ptr[i]) and (*ptr)[i]
// OP desired function
(*ptr)[i] = 'x';
// Dereference ptr, getting the address of a char *array.
// Assign 'x' to the i'th element of that char * array.
// OP post with the undesired function
*(ptr[i]) = 'x';
// This is like
char *q = ptr[i];
*q = 'x';
// This make sense _if_ ptr were an array of char *.
// Get the i'th char * from ptr and assign to q.
// Assign 'x' to to the location pointer to by q.
This is all the code needed...
nothing more...
void myFunc(char **pp, char * str){
*pp = str;
}
The only issue here is that "Hello" resides in read only section because it is a constant string... so you can't change "Hello" to something else...

Run-time error in program

int main()
{
char *p="abcd";
while(*p!='\0') ++*p++;
printf("%s",p);
return 0;
}
I am not able to understand why the code does not run. The problem is in the statement ++*p++, but what is the problem?
P points to constant string literal *p="abcd"; by doing ++*p++ you are trying to modify string '"abcd"', for example a in string will be increment to 'b' because of ++*p that is undefined behavior (constant string can't change). it may cause a segmentation fault.
`++*p++` means `++*p` then `p++`
^
| this operation try to modify string constant
char *p="abcd";
p is pointing to a readonly segment and you can not increment p as you did here
while(*p!='\0') ++*p++;
//char *p="abcd";//"string" is const char, don't change.
char str[]="abcd";//is copied, including the '\0' to reserve space
char *p = str;
while(*p!='\0') ++*p++;
//printf("%s",p);//address pointing of 'p' has been changed
printf("%s",str);//display "bcde"
char *foo = "abcd";
char bar[] = "abcd";
Consider the differences between foo and bar. foo is a pointer that's initialised to point to memory reserved for a string literal. bar is an array with it's own memory that's initialised to a string literal; it's value is copied from the string literal during initialisation. It is appropriate to modify bar[0], etc, but not foo[0]. Hence, you need an array declaration.
However, you can't increment an array declaration; That's an operation for pointer variables or integer variables. Additionally, your loop changes where p points at, before it's printed, so you need to keep the original location of your string somewhere. Hence, you also need a pointer, or an integer declaration.
With this in mind, it might seem like a good idea to change your code to something like this:
int main()
{
char str[] = "abcd";
/* Using a pointer variable: */
for (char *ptr = str; *ptr != '\0'; ++*ptr++);
/* Using a size_t variable: */
for (size_t x = 0; str[x] != '\0'; str[x++]++);
printf("%s", str);
return 0;
}

Why does *(str+i) = *(str +j) not work here?

void reverse(char *str){
int i,j;
char temp;
for(i=0,j=strlen(str)-1; i<j; i++, j--){
temp = *(str + i);
*(str + i) = *(str + j);
*(str + j) = temp;
printf("%c",*(str + j));
}
}
int main (int argc, char const *argv[])
{
char *str = "Shiv";
reverse(str);
printf("%s",str);
return 0;
}
When I use char *str = "Shiv" the lines in the swapping part of my reverse function i.e str[i]=str[j] dont seem to work, however if I declare str as char str[] = "Shiv", the swapping part works? What is the reason for this. I was a bit puzzled by the behavior, I kept getting the message "Bus error" when I tried to run the program.
When you use char *str = "Shiv";, you don't own the memory pointed to, and you're not allowed to write to it. The actual bytes for the string could be a constant inside the program's code.
When you use char str[] = "Shiv";, the 4(+1) char bytes and the array itself are on your stack, and you're allowed to write to them as much as you please.
The char *str = "Shiv" gets a pointer to a string constant, which may be loaded into a protected area of memory (e.g. part of the executable code) that is read only.
char *str = "Shiv";
This should be :
const char *str = "Shiv";
And now you'll have an error ;)
Try
int main (int argc, char const *argv[])
{
char *str = malloc(5*sizeof(char)); //4 chars + '\0'
strcpy(str,"Shiv");
reverse(str);
printf("%s",str);
free(str); //Not needed for such a small example, but to illustrate
return 0;
}
instead. That will get you read/write memory when using pointers. Using [] notation allocates space in the stack directly, but using const pointers doesn't.
String literals are non-modifiable objects in both C and C++. An attempt to modify a string literal always results in undefined behavior. This is exactly what you observe when you get your "Bus error" with
char *str = "Shiv";
variant. In this case your 'reverse' function will make an attempt to modify a string literal. Thus, the behavior is undefined.
The
char str[] = "Shiv";
variant will create a copy of the string literal in a modifiable array 'str', and then 'reverse' will operate on that copy. This will work fine.
P.S. Don't create non-const-qualified pointers to string literals. You first variant should have been
const char *str = "Shiv";
(note the extra 'const').
String literals (your "Shiv") are not modifiable.
You assign to a pointer the address of such a string literal, then you try to change the contents of the string literal by dereferencing the pointer value. That's a big NO-NO.
Declare str as an array instead:
char str[] = "Shiv";
This creates str as an array of 5 characters and copies the characters 'S', 'h', 'i', 'v' and '\0' to str[0], str[1], ..., str[4]. The values in each element of str are modifiable.
When I want to use a pointer to a string literal, I usually declare it const. That way, the compiler can help me by issuing a message when my code wants to change the contents of a string literal
const char *str = "Shiv";
Imagine you could do the same with integers.
/* Just having fun, this is not C! */
int *ptr = &5; /* address of 5 */
*ptr = 42; /* change 5 to 42 */
printf("5 + 1 is %d\n", *(&5) + 1); /* 6? or 43? :) */
Quote from the Standard:
6.4.5 String literals
...
6 ... If the program attempts to modify such an array [a string literal], the behavior is undefined.
char *str is a pointer / reference to a block of characters (the string). But its sitting somewhere in a block of memory so you cannot just assign it like that.
Interesting that I've never noticed this. I was able to replicate this condition in VS2008 C++.
Typically, it is a bad idea to do in-place modification of constants.
In any case, this post explains this situation pretty clearly.
The first (char[]) is local data you can edit
(since the array is local data).
The second (char *) is a local pointer to
global, static (constant) data. You
are not allowed to modify constant
data.
If you have GNU C, you can compile
with -fwritable-strings to keep the
global string from being made
constant, but this is not recommended.

Resources