Dereferencing a character pointer in C - c

Here is my code:
char *str = malloc(100*sizeof(char));
*str ="Hello"; // or pass it any string
Now I want to pass str in the function:
sys_open(const char * filename, int flags, int mode)
When I use a char array as the second parameter, it works, but using the pointer whose value was copied over does not work.
I can achieve what I want with a char array, but why can't I do the same with a pointer?

You can't assign strings that way in C. You'll need to use strcpy(3) or one of its relatives.

There are a few things wrong:
*str = "Hello"; // or pass it any string
str is char*, *str is a char, and "Hello" is a const char* (well, actually const char[6] that decays into const char*). It's illegal to assign a const char* to a char.
Assuming you meant str = "Hello";, that's still wrong because it's reassigning the pointer str to point to the string literal "Hello". The memory you previously allocated with malloc now has nothing pointing to it, and you've leaked memory.
Passing str to sys_read as you're doing won't work. str is pointing to a string literal not to the writable memory that you've allocated. Not only will the count be wrong, but sys_read won't be able to write to it at all. (String literals are immutable, and attempting to modify one will result in undefined behavior.)

In the program, I feel that there is a type-cast missing as malloc returns a void * and assigning the same to char * gives an error.

Related

Assigning a string to a pointer

I just wanted to ask this:
In this piece of code I create a string and a pointer, what is the correct way to assign this string to the pointer?
char str[10] = "hello";
char* ptr
Does it work with ptr = str?
If not, why?
What is the correct way to assign this string to the pointer?
None. You cannot assign a string to a pointer. You only can assign the pointer by the address of the first element of the array str, which was initialized by the string "hello". It's a subtle but important difference.
Does it work with ptr = str?
Yes, but it doesn't assign the string to the pointer. str decays to a pointer to the first element of the array of char str. After that, ptr is pointing to the array str which contains the string "hello".
If you don't want to modify the string, You could simplify the code by initializing the pointer to point to a string literal, which is stored in read-only memory instead of an modifiable array of char:
const char* ptr = "hello";

What is the difference between char s[] and char *s when it comes to initialisation? [duplicate]

This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Closed 3 years ago.
with string literal declaration like this:
char str[] = "hello";
and this
char *ptr = "hello";
initialisation of ptr with str is possible:
ptr = str; //valid
but not viceversa:
str = ptr; //invalid
although str being a char array would hold the address of the first element anyways, then what makes the second case invalid and not the first one?
Here
char str[] = "hello";
char *ptr = str; /* valid */
above pointer assignment char *ptr = str; is valid as ptr is pointer and its assigned with str which points to base address of str, and in this case ptr is not a constant pointer i.e it can point to different memory location, hence it can be assigned like ptr = str.
But in below case
char *ptr = "hello";
char str[10] = ptr; /* invalid */
the statement char str[10] = ptr; is not valid as str name itself represents one address and by doing char str[10] = ptr; you are trying to modify the base address of str which is not possible because array is not a pointer.
At very first, the string "hello" actually is an array located somewhere in (immutable!) memory.
You can assign it to a pointer, which is what you do in second example (char* ptr = ...). In this case, the pointer just points to that immutable array, i. e. holds the array's address. Recommendation at this point: Although legal in C (unlike C++), don't assign string literals to char* pointers, assign them only to char const* pointers; this reflects immutability much better.
In the second example, you use the first array (the literal) to initialise another array (str). This other array str (if not provided explicit length, as in the example) will use the first array's length and copy the contents of. This second array isn't immutable any more and you can modify it (as long as you do not exceed its bounds).
Assignment: Arrays decay to pointers automatically, if the context they are used in requires a pointer. This is why your first assignment example works, you assign a pointer (the one the array decayed to) to another one (ptr). Actually, exactly the same as in your second initialisation example, you don't do anything different there either...
But arrays aren't pointers, and pointers never decay backwards to arrays. This is why the second assignment example doesn't work.

Why does strcpy fail with char *s but not with char s[1024]?

Why does the following happen:
char s[2] = "a";
strcpy(s,"b");
printf("%s",s);
--> executed without problem
char *s = "a";
strcpy(s,"b");
printf("%s",s);
--> segfault
Shouldn't the second variation also allocate 2 bytes of memory for s and thus have enough memory to copy "b" there?
char *s = "a";
The pointer s is pointing to the string literal "a". Trying to write to this has undefined behaviour, as on many systems string literals live in a read-only part of the program.
It is an accident of history that string literals are of type char[N] rather than const char[N] which would make it much clearer.
Shouldn't the second variation also allocate 2 bytes of memory for s and thus have enough memory to copy "b" there?
No, char *s is pointing to a static memory address containing the string "a" (writing to that location results in the segfault you are experiencing) whereas char s[2]; itself provides the space required for the string.
If you want to manually allocate the space for your string you can use dynamic allocation:
char *s = strdup("a"); /* or malloc(sizeof(char)*2); */
strcpy(s,"b");
printf("%s",s); /* should work fine */
Don't forget to free() your string afterwards.
Altogather a different way/answer : I think the mistake is that you are not creating a variable the pointer has to point to and hence the seg fault.
A rule which I follow : Declaring a pointer variable will not create the type of variable, it points at. It creates a pointer variable. So in case you are pointing to a string buffer you need to specify the character array and a buffer pointer and point to the address of the character array.

Difference between char* and char** (in C)

I have written this code which is simple
#include <stdio.h>
#include <string.h>
void printLastLetter(char **str)
{
printf("%c\n",*(*str + strlen(*str) - 1));
printf("%c\n",**(str + strlen(*str) - 1));
}
int main()
{
char *str = "1234556";
printLastLetter(&str);
return 1;
}
Now, if I want to print the last char in a string I know the first line of printLastLetter is the right line of code. What I don't fully understand is what the difference is between *str and **str. The first one is an array of characters, and the second??
Also, what is the difference in memory allocation between char *str and str[10]?
Thnks
char* is a pointer to char, char ** is a pointer to a pointer to char.
char *ptr; does NOT allocate memory for characters, it allocates memory for a pointer to char.
char arr[10]; allocates 10 characters and arr holds the address of the first character. (though arr is NOT a pointer (not char *) but of type char[10])
For demonstration: char *str = "1234556"; is like:
char *str; // allocate a space for char pointer on the stack
str = "1234556"; // assign the address of the string literal "1234556" to str
As #Oli Charlesworth commented, if you use a pointer to a constant string, such as in the above example, you should declare the pointer as const - const char *str = "1234556"; so if you try to modify it, which is not allowed, you will get a compile-time error and not a run-time access violation error, such as segmentation fault. If you're not familiar with that, please look here.
Also see the explanation in the FAQ of newsgroup comp.lang.c.
char **x is a pointer to a pointer, which is useful when you want to modify an existing pointer outside of its scope (say, within a function call).
This is important because C is pass by copy, so to modify a pointer within another function, you have to pass the address of the pointer and use a pointer to the pointer like so:
void modify(char **s)
{
free(*s); // free the old array
*s = malloc(10); // allocate a new array of 10 chars
}
int main()
{
char *s = malloc(5); // s points to an array of 5 chars
modify(&s); // s now points to a new array of 10 chars
free(s);
}
You can also use char ** to store an array of strings. However, if you dynamically allocate everything, remember to keep track of how long the array of strings is so you can loop through each element and free it.
As for your last question, char *str; simply declares a pointer with no memory allocated to it, whereas char str[10]; allocates an array of 10 chars on the local stack. The local array will disappear once it goes out of scope though, which is why if you want to return a string from a function, you want to use a pointer with dynamically allocated (malloc'd) memory.
Also, char *str = "Some string constant"; is also a pointer to a string constant. String constants are stored in the global data section of your compiled program and can't be modified. You don't have to allocate memory for them because they're compiled/hardcoded into your program, so they already take up memory.
The first one is an array of characters, and the second??
The second is a pointer to your array. Since you pass the adress of str and not the pointer (str) itself you need this to derefence.
printLastLetter( str );
and
printf("%c\n",*(str + strlen(str) - 1));
makes more sense unless you need to change the value of str.
You might care to study this minor variation of your program (the function printLastLetter() is unchanged except that it is made static), and work out why the output is:
3
X
The output is fully deterministic - but only because I carefully set up the list variable so that it would be deterministic.
#include <stdio.h>
#include <string.h>
static void printLastLetter(char **str)
{
printf("%c\n", *(*str + strlen(*str) - 1));
printf("%c\n", **(str + strlen(*str) - 1));
}
int main(void)
{
char *list[] = { "123", "abc", "XYZ" };
printLastLetter(list);
return 0;
}
char** is for a string of strings basically - an array of character arrays. If you want to pass multiple character array arguments you can use this assuming they're allocated correctly.
char **x;
*x would dereference and give you the first character array allocated in x.
**x would dereference that character array giving you the first character in the array.
**str is nothing else than (*str)[0] and the difference between *str and str[10] (in the declaration, I assume) I think is, that the former is just a pointer pointing to a constant string literal that may be stored somewhere in global static memory, whereas the latter allocates 10 byte of memory on the stack where the literal is stored into.
char * is a pointer to a memory location. for char * str="123456"; this is the first character of a string. The "" are just a convenient way of entering an array of character values.
str[10] is a way of reserving 10 characters in memory without saying what they are.(nb Since the last character is a NULL this can actually only hold 9 letters. When a function takes a * parameter you can use a [] parameter but not the other way round.
You are making it unnecessarily complicated by taking the address of str before using it as a parameter. In C you often pass the address of an object to a function because it is a lot faster then passing the whole object. But since it is already a pointer you do not make the function any better by passing a pointer to a pointer. Assuming you do not want to change the pointer to point to a different string.
for your code snippet, *str holds address to a char and **str holds address to a variable holding address of a char. In another word, pointer to pointer.
Whenever, you have *str, only enough memory is allocated to hold a pointer type variable(4 byte on a 32 bit machine). With str[10], memory is already allocated for 10 char.

How to change a character in a string using pointers?

im having troubles with this code
int main() {
char *My_St = "abcdef";
*(My_St+1)='+';
printf("%s\n",My_St);
return 0;
}
i built this code and has no errors, but when i try to run it, it throws a segmentation fault, could someone tell what's wrong
You can't because you are trying to modify const data.
change it to:
char My_St[] = "abcdef";
Then you will be able to change it.
Think about what you were doing, you were declaring a pointer that pointed to "abcdef". It IS a pointer, not an array of chars. "abcdef" lives in the farm, I mean, in the .text area of your program and that is immutable.
When you do it the way I've shown, you are telling the compiler: i'm declaring this array, that will have as many chars as are needed to accommodate "abcdef" and also, as you are there, copy "abcdef" to it.
You provided a hint to the compiler by declaring My_St with type char *. Assigning a string literal to this pointer essentially makes it a const char * because a string literal cannot be modified, meaning the memory location is read-only. Writing to that read-only memory location is what is producing your segfault. Change it from char *My_St to char My_St[] to get it working.
char *My_St refers to constant memory, most likely. You will need to dynamically allocate your string and then fill it (using strcpy).
char *str = malloc(7);
strcpy(str, "abcdef");
Or
char *str = strdup("abcdef");
And then it is safe to modify str.
The basics are correct, however your character string is (behind the scenes) constant and can't be modified. You'd have to define a array of chars (e.g. char[20]), copy the string into it and then modify the character.
To be 100% correct you'd have to write const char *My_St = "abcdef"; which makes it clearer that you can't do what you're trying to do.

Resources