This might just be the dumbest question, but i havent found any explanation when it comes to char, just when it comes to int, which i can manage.
However, i got this huge problem, i've pointed the adress of my pointer to a char and from that char i want to print out the value.
This is how my code looks:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char *pn) {
char text[64];
char nei;
text[64] = &pn;
printf("%s\n", *text[64]);
}
int main()
{
function("Hello");
getchar();
return(0);
}
I can't figure out whats wrong with it to be honest. Why cant I put a * in front of text[64], since thats how you print the value, correct?
'*' has meaning when applied to a pointer. Applied to a char, I'm not sure what it would do. So, no, putting a * in front of text[64] is not how you print the value.
In your code text is a 64 byte long array of char. Valid indexes into it are 0 to 63.
The expression text[64] refers to memory you don't have access to, or may be a reference into one of your other automatic variables. text[64] is beyond the end of the array.
void function(char *pn) {
char text[64];
char nei;
text[64] = &pn; /* <- this won't work */
strcpy(text, pn); /* <- probably will work, may overflow text if string at pn is too long */
printf("%s\n", *text[64]); /* <- this won't work */
printf("%s\n", pn); /* <- probably will work */
printf("%s\n", text); /* after strcpy above, will likely work */
}
You cannot use both * and [ ], and also text[64] is out of bounds as its said in comment. You can use function strcpy to copy one string to another.
char text[64]; declares text as an array of 64 characters.
printf("%s\n", *text[64]) makes no sense, because:
text[64] points to the character after the end of the array; i.e. text[63] is the last character in the array.
*text[64] attempts to dereference the 64th item in the text array. But each item is not a pointer, but a character.
Perhaps you meant &text[n] where n is a number between 0 and 63, which would be a pointer to a character within the array, and hence a string. In C a string (what %s expects) is a pointer to a character, and the string is that character and all following up until a NUL.
This bit of your question is unclear:
Why cant I put a * in front of text[64],
(answered above)
since thats how you print the value, correct
I have no idea what that bit means. As per the above, %s expects a char *, i.e. a pointer to a character.
If you are trying to copy the contents of the pointer *pn to the character array text then you better use strcpy() function.
strcpy(text,pn);
will let you copy the contents.
You trying to print out the contents of the array. you can't use the * and [] together.
In case of a array
for example
char text[64]
as you have mentioned in your code
printf("%x",text);
will print the start of the allocated memory where the array lies.
when you do text[0] the start of the allocated memory address will be added with 0 and the contents of that memory will given back.
This is how an array work
Now if you are to use a dereferencing operator * then *text will give the 0th element of the array
*(text + 1)
will give you the second element of the array and so and so forth.
one more thing you can't use
printf("%s",text);
as the value that you are passing to the function is not a string but a character array as it does not have '\0' at its end.
Why cant I put a * in front of text[64]
You can! but not the way you have tried to do it.
For example, in a declaration, char *text[64]; would be used to create an array of strings, each 64 bytes in length. And would require allocation of memory using malloc()orcalloc()`, or an initializer such as:
char *text[64]={"this is a string1","this is string2"};
Which creates an array of 2 strings, each with 64 bytes (although only partially used), which could be used like this:
printf("%s\n", text[0]);
printf("%s\n", text[1]);
since that's how you print the value, correct? (referring to:printf("%s\n", *text[64]);)
No.
The argument char *pn refers to a single string.
If you want to copy this argument to the local variable:
First, change the line:
text[64] = &pn;
to
if(!pn) return; //test and leave if pn is null pointer
strcpy(text, pn);
Then just use:
printf("%s\n", text);
to print the line
Related
When studying string manipulation in C, I've come across an effect that's not quite what I would have expected with strcat(). Take the following little program:
#include <stdio.h>
#include <string.h>
int main()
{
char string[20] = "abcde";
strcat(string + 1, "fghij");
printf("%s", string);
return 0;
}
I would expect this program to print out bcdefghij. My thinking was that in C, strings are arrays of characters, and the name of an array is a pointer to its first element, i.e., the element with index zero. So the variable string is a pointer to a. But if I calculate string + 1 and use that as the destination array for concatenation with strcat(), I get a pointer to a memory address that's one array element (1 * sizeof(char), in this case) away, and hence a pointer to the b. So my thinking was that the target destination is the array starting with b (and ending with the invisible null character), and to that the fghij is concatenated, giving me bcdefghij.
But that's not what I get - the output of the program is abcdefghij. It's the exact same output as I would get with strcat(string, "fghij"); - the addition of the 1 to string is ignored. I also get the same output with an addition of another number, e.g. strcat(string + 4, "fghij");, for that matter.
Can somebody explain to me why this is the case? My best guess is that it has to do with the binding precedence of the + operator, but I'm not sure about this.
Edit: I increased the size of the original array with char string[20] so that it will, in any case, be big enough to hold the concatenated string. Output is still the same, which I think means the array overflow is not key to my question.
You will get an output of abcdefghij, because your call to strcat hasn't changed the address of string (and nor can you change that – it's fixed for the duration of the block in which it is declared, just like the address of any other variable). What you are passing to strcat is the address of the second element of the string array: but that is still interpreted as the address of a nul-terminated string, to which the call appends the second (source) argument. Appending that second argument's content to string, string + 1 or string + n will produce the same result in the string array, so long as there is a nul-terminator at or after the n index.
To print the value of the string that you actually pass to the strcat call (i.e., starting from the 'b' character), you can save the return value of the call and print that:
#include <stdio.h>
#include <string.h>
int main()
{
char string[20] = "abcde";
char* result = strcat(string + 1, "fghij"); // strcat will return the "string + 1" pointer
printf("%s", result); // bcdefghij
return 0;
}
char string[] = "abcde";
strcat(string + 1, "fghij");
Append five characters to a full string array. Booom. Undefined behavior.
Adding something to a string array is a performance optimization that tells the runtime that the string is known to be at least that many characters long.
You seem to believe that a string is a thing of its own and not an array, and strcat is doing something to its first argument. That's not how that works. Strings are arrays*; and strcat is modifying the array contents.
*Somebody's going to come by and claim that heap allocated strings are not arrays. OP is not dealing with heap yet.
Arrays are non-modibfiable lvalues. For example you may not write
char string[20] = "abcde";
char string2[] = ""fghij"";
string = string2;
Used in expressions arrays with rare exceptions are implicitly converted to pointers to their first elements.
If you will write for example string + 1 then the address of the array will not be changed.
In this call
strcat(string + 1, "fghij");
elements of the array string are being overwritten starting from the second element of the array.
In this statement
printf("%s", string);
there is outputted the whole array starting from its first character (again the array designator used as an argument is converted to a pointer to its first element).
You could write for example
printf("%s", string + 1);
In this case the array is outputted starting from its second element.
These are just two pointers to different parts of the same memory inside the same array. There is nothing in your code which creates a second array. "the name of an array is a pointer to its first element" well, not really, it decays into a pointer to its first element whenever used in an expression. So in case of string + 1, this decay first happens to the string operand and then you get pointer arithmetic afterwards. You can actually never do pointer arithmetic on array types, only on decayed pointers. Details here: Do pointers support "array style indexing"?
As for strcat, it basically does two things: call strlen on the original string to find where it ends, then call strcpy to append the new string at the position where the null terminator was stored. It's the very same thing as typing strcpy(&src[strlen(src)], dst);
Therefore it won't matter if you pass string + 1 or string, because in either case strcat will look for the null terminator and nothing else.
I am practicing allocation memory using malloc() with pointers, but 1 observation about pointers is that, why can strcpy() accept str variable without *:
char *str;
str = (char *) malloc(15);
strcpy(str, "Hello");
printf("String = %s, Address = %u\n", str, str);
But with integers, we need * to give str a value.
int *str;
str = (int *) malloc(15);
*str = 10;
printf("Int = %d, Address = %u\n", *str, str);
it really confuses me why strcpy() accepts str, because in my own understanding, "Hello" will be passed to the memory location of str that will cause some errors.
In C, a string is (by definition) an array of characters. However (whether we realize it all the time or not) we almost always end up accessing arrays using pointers. So, although C does not have a true "string" type, for most practical purposes, the type pointer-to-char (i.e. char *) serves this purpose. Almost any function that accepts or returns a string will actually use a char *. That's why strlen() and strcpy() accept char *. That's why printf %s expects a char *. In all of these cases, what these functions need is a pointer to the first character of the string. (They then read the rest of the string sequentially, stopping when they find the terminating '\0' character.)
In these cases, you don't use an explicit * character. * would extract just the character pointed to (that is, the first character of the string), but you don't want to extract the first character, you want to hand the whole string (that is, a pointer to the whole string) to strcpy so it can do its job.
In your second example, you weren't working with a string at all. (The fact that you used a variable named str confused me for a moment.) You have a pointer to some ints, and you're working with the first int pointed to. Since you're directly accessing one of the things pointed to, that's why you do need the explicit * character.
The * is called indirection or dereference operator.
In your second code,
*str = 10;
assigns the value 10 to the memory address pointed by str. This is one value (i.e., a single variable).
OTOTH, strcpy() copies the whole string all at a time. It accepts two char * parameters, so you don't need the * to dereference to get the value while passing arguments.
You can use the dereference operator, without strcpy(), copying element by element, like
char *str;
str = (char *) malloc(15); //success check TODO
int len = strlen("Hello"); //need string.h header
for (i = 0; i < len; i ++)
*(str+i)= "Hello"[i]; // the * form. as you wanted
str[i] = 0; //null termination
Many string manipulation functions, including strcpy, by convention and design, accept the pointer to the first character of the array, not the pointer to the whole array, even though their values are the same.
This is because their types are different; e.g. a pointer to char[10] has a different type from that of a pointer to char[15], and passing around the pointer to the whole array would be impossible or very clumsy because of this, unless you cast them everywhere or make different functions for different lengths.
For this reason, they have established a convention of passing around a string with the pointer to its first character, not to the whole array, possibly with its length when necessary. Many functions that operate on an array, such as memset, work the same way.
Well, here's what happens in the first snippet :
You are first dynamically allocating 15 bytes of memory, storing this address to the char pointer, which is pointer to a 1-byte sequence of data (a string).
Then you call strcpy(), which iterates over the string and copy characters, byte per byte, into the newly allocated memory space. Each character is a number based on the ASCII table, eg. character a = 97 (take a look at man ascii).
Then you pass this address to printf() which reads from the string, byte per byte, then flush it to your terminal.
In the second snippet, the process is the same, you are still allocating 15 bytes, storing the address in an int * pointer. An int is a 4 byte data type.
When you do *str = 10, you are dereferencing the pointer to store the value 10 at the address pointed by str. Remind what I wrote ahead, you could have done *str = 'a', and this index 0 integer would had the value 97, even if you try to read it as an int. you can event print it if you would.
So why strcpy() can take a int * as parameter? Because it's a memory space where it can write, byte per byte. You can store "Hell" in an int, then "o!" in the next one.
It's just all about usage easiness.
See there is a difference between = operator and the function strcpy.
* is deference operator. When you say *str, it means value at the memory location pointed by str.
Also as a good practice, use this
str = (char *) malloc( sizeof(char)*15 )
It is because the size of a data type might be different on different platforms. Hence use sizeof function to determine its actual size at the run time.
Hi I have a simple question
char *a="abc";
printf("%s\n",a);
int *b;
b=1;
printf("%d\n",b);
Why the first one works but the second one doesnot work?
I think the first one should be
char *a="abc";
printf("%s\n",*a);
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
Thanks
Ying
Why the first one works but the second one doesnot work?
Because in the first, you're not asking it to print a character, you're asking it to print a null-terminated array of characters as a string.
The confusion here is that you're thinking of strings as a "native type" in the same way as integers and characters. C doesn't work that way; a string is just a pointer to a bunch of characters ending with a null byte.
If you really want to think of strings as a native type (keeping in mind that they really aren't), think of it this way: the type of a string is char *, not char. So, printf("%s\n", a); works because you're passing a char * to match with a format specifier indicating char *. To get the equivalent problems as with the second example, you'd need to pass a pointer to a string—that is, a char **.
Alternatively, the equivalent of %d is not %s, but %c, which prints a single character. To use it, you do have to pass it a character. printf("%c\n", a) will have the same problem as printf("%d\n", b).
From your comment:
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
This is where the loose thinking of strings as native objects falls down.
When you write this:
char *a = "abc";
What happens is that the compiler stores a array of four characters—'a', 'b', 'c', and '\0'—somewhere, and a points at the first one, the a. As long as you remember that "abc" is really an array of four separate characters, it makes sense to think of a as a pointer to that thing (at least if you understand how arrays and pointer arithmetic work in C). But if you forget that, if you think a is pointing at a single address that holds a single object "abc", it will confuse you.
Quoting from the GNU printf man page (because the C standard isn't linkable):
d, i
The int argument is converted to signed decimal notation …
c
… the int argument is converted to an unsigned char, and the resulting character is written…
s
… The const char * argument is expected to be a pointer to an array of character type (pointer to a string). Characters from the array are written up to (but not including) a terminating null byte ('\0') …
One last thing:
You may be wondering how printf("%s", a) or strchr(a, 'b') or any other function can print or search the string when there is no such value as "the string".
They're using a convention: they take a pointer to a character, and print or search every character from there up to the first null. For example, you could write a print_string function like this:
void print_string(char *string) {
while (*string) {
printf("%c", *string);
++string;
}
}
Or:
void print_string(char *string) {
for (int i=0; string[i]; ++i) {
printf("%c", string[i]);
}
}
Either way, you're assuming the char * is a pointer to the start of an array of characters, instead of just to a single character, and printing each character in the array until you hit a null character. That's the "null-terminated string" convention that's baked into functions like printf, strstr, etc. throughout the standard library.
Strings aren't really "first-class citizens" in C. In reality, they're just implemented as null-terminated arrays of characters, with some syntactic sugar thrown in to make programmers' lives easier. That means when passing strings around, you'll mostly be doing it via char * variables - that is, pointers to null-terminated arrays of char.
This practice holds for calling printf, too. The %s format is matched with a char * parameter to print the string - just as you've seen. You could use *a, but you'd want to match that with a %c or an integer format to print just the single character pointed to.
Your second example is wrong for a couple of reasons. First, it's not legal to make the assignment b = 1 without an explicit cast in C - you'd need b = (int *)1. Second, you're trying to print out a pointer, but you're using %d as a format string. That's wrong too - you should use %p like this: printf("%p\n", (void *)b);.
What it really looks like you're trying to do in the second example is:
int b = 1;
int *p = &b;
printf("%d\n", *p);
That is, make a pointer to an integer, then dereference it and print it out.
Editorial note: You should get a good beginner C book (search around here and I'm sure you'll find suggestions) and work through it.
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.
I was under the impression that they were the same thing. However, it looks to my like they are being treated differently here. The part I am confused about looks like this.
Foo* initFoo(char* name);
int main
{
Foo* foo;
char* player_name[25];
scanf("%s", player_name);
foo = initFoo(player_name);
}
Foo* initFoo(char* name)
{
printf("\n%s", name);
}
The string prints out fine. However, I get a compiler warning that says: passing argument 1 of 'initFoo' from incompatible pointer type.
What am I missing about pointers?
A string is an array of characters. What you have here is an array of pointers to characters.
The line:
char* player_name[25];
allocates a 25 element array of pointers to char. A pointer to char is generally considered a string, so this declaration could be interpreted as an array of strings, but the memory for storing those strings does not exist yet. You would have to allocate those string separately.
Assuming pointers are 4 bytes on your machine, this line would have the effect of allocating 25 x 4 = 100 bytes.
In C, when you use an array name without a subscript, it "decomposes" into a pointer to the first element of the array.
So... when this line is executed:
scanf("%s", player_name);
player_name points to 100 bytes of memory, enough room enough to hold 100 characters that are read in (well 99 characters plus a terminating NUL byte). The compiler is not protecting you from storing those characters in the memory that was allocated for 25 pointers.
Finally:
foo = initFoo(player_name);
is passing the starting address of the array to the function initFoo(). The compiler knows this is probably wrong since initFoo() is supposed to take a pointer to chars, not at pointer to an array of char pointers, but it lets you do it anyway except for the warning. The printf() statement in initFoo() reinterprets that pointer as a char pointer, and you get the correct results!
As others have said, it would be correct to change the one line to
char player_name[25];
which declares an array of 25 characters.
char* player_name[25]; /* means an array of character pointers. */
char player_name[25]; /* will get rid of the warning */
To fix it change to:
char player_name[25];