I am not able to understand the difference between strcpy function and the method of equating the addresses of the strings using a pointer.The code given below would make my issue more clear. Any help would be appreciated.
//code to take input of strings in an array of pointers
#include <stdio.h>
#include <strings.h>
int main()
{
//suppose the array of pointers is of 10 elements
char *strings[10],string[50],*p;
int length;
//proper method to take inputs:
for(i=0;i<10;i++)
{
scanf(" %49[^\n]",string);
length = strlen(string);
p = (char *)malloc(length+1);
strcpy(p,string);//why use strcpy here instead of p = string
strings[i] = p; //why use this long way instead of writing directly strcpy(strings[i],string) by first defining malloc for strings[i]
}
return 0;
}
A short introduction into the magic of pointers:
char *strings[10],string[50],*p;
These are three variables with distinct types:
char *strings[10]; // an array of 10 pointers to char
char string[50]; // an array of 50 char
char *p; // a pointer to char
Then the followin is done (10 times):
scanf(" %49[^\n]",string);
Read C string from input and store it into string considering that a 0 terminator must fit in also.
length = strlen(string);
Count non-0 characters until 0 terminator is found and store in length.
p = (char *)malloc(length+1);
Allocate memory on heap with length + 1 (for 0 terminator) and store address of that memory in p. (malloc() might fail. A check if (p != NULL) wouldn't hurt.)
strcpy(p,string);//why use strcpy here instead of p = string
Copy C string in string to memory pointed in p. strcpy() copies until (inclusive) 0 terminator is found in source.
strings[i] = p;
Assign p (the pointer to memory) to strings[i]. (After assignment strings[i] points to the same memory than p. The assignment is a pointer assignment but not the assignment of the value to which is pointed.)
Why strcpy(p,string); instead of p = string:
The latter would assign address of string (the local variable, probably stored on stack) to p.
The address of allocated memory (with malloc()) would have been lost. (This introduces a memory leak - memory in heap which cannot be addressed by any pointer in code.)
p would now point to the local variable in string (for every iteration in for loop). Hence afterwards, all entries of strings[10] would point to string finally.
char *strings[10]---- --------->1.
strcpy(strings[i],string) ----->2.
strings[i] = string ----------->3.
p = (char *)malloc(length+1); -|
strcpy(p,string); |-> 4.
strings[i] = p;----------------|
strings is an array of pointers, each pointer must point to valid memory.
Will lead undefined behavior since strings[i] is not pointing to valid memory.
Works but every pointer of strings will point to same location thus each will have same contents.
Thus create the new memory first, copy the contents to it and assign that memory to strings[i]
strcpy copies a particular string into allocated memory. Assigning pointers doesn't actually copy the string, just sets the second pointer variable to the same value as the first.
strcpy(char *destination, char *source);
copies from source to destination until the function finds '\0'. This function is not secure and should not be used - try strncpy or strlcpy instead. You can find useful information about these two functions at https://linux.die.net/man/3/strncpy - check where your code is going to run in order to help you choose the best option.
In your code block you have this declaration
char *strings[10],string[50],*p;
This declares three pointers, but they are quite different. *p is an ordinary pointer, and must have space allocated for it (via malloc) before you can use it. string[50] is also a pointer, but of length 50 (characters, usually 1 byte) - and it's allocated on the function stack directly so you can use it right away (though the very first use of it should be to zero out the memory unless you've used a zeroing allocator like Solaris' calloc. Finally, *strings[10] is a double pointer - you have allocated an array of 10 pointers, each element of which (strings[1], strings[9] etc) must be allocated for before use.
The only one of those which you can assign to immediately is string, because the space is already allocated. Each of those pointers can be addressed via subscripts - but in each case you must ensure that you do not walk off the end otherwise you'll incur a SIGSEGV "segmentation violation" and your program will crash. Or at least, it should, but you might instead get merely weird results.
Finally, pointers allocated to must be freed manually otherwise you'll have memory leaks. Items allocated on the stack (string) do not need to be freed because the compiler handles that for you when the function ends.
I am confused about some basics in C string declaration. I tried out the following code and I noticed some difference:
char* foo(){
char* str1="string";
char str2[7]="string";
char* str3=(char)malloc(sizeof(char)*7);
return str1;
/* OR: return str2; */
/* OR: return str3; */
}
void main() {
printf("%s",foo());
return 0;
}
I made foo() return str1/2/3 one at a time, and tried to print the result in the main. str2 returned something weird, but str1 and str3 returned the actual "string".
1.Now, what's the difference between the three declarations? I think the reason why str2 didn't work is because it is declared as a local variable, is that correct?
2.Then what about str1? If the result remains after the foo() ended, wouldn't that cause memory leak?
3.I'm simply trying to write a function that returns a string in C, and use the value returned by that function for other stuff, which str declaration above should I use?
Thanks in advance!
char* str1="string";
This makes str1 a pointer; it points to the first character of the string literal. You should define it as const, because you're not allowed to modify a string literal:
const char *str1 = "string";
...
char str2[7]="string";
This makes str2 an array of char (not a pointer), and copies the contents of the string literal into it. There's no need to define it as const; the array itself is writable. You can also omit the size and let it be determined by the initializer:
char str2[] = "string";
Then sizeof str2 == 7 (6 bytes for "string" plus 1 for the terminating '\0').
This:
char* str3=(char)malloc(sizeof(char)*7);
is written incorrectly, and it shouldn't even compile; at the very least, you should have gotten a warning from your compiler. You're casting the result of malloc() to type char. You should be converting it to char*:
char *str3 = (char*)malloc(sizeof(char) * 7);
But the cast is unnecessary, and can mask errors in some cases; see question 7.7 and following in the comp.lang.c FAQ:
char *str3 = malloc(sizeof(char) * 7);
But sizeof(char) is 1 by definition, so you can just write:
char *str3 = malloc(7);
malloc() allocates memory, but it doesn't initialize it, so if you try to print the string that str3 points to, you'll get garbage -- or even a run-time crash if the allocated space doesn't happen to contain a terminating null character '\0'. You can initialize it with strcpy(), for example:
char *str3 = malloc(7);
if (str3 == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(str3, "string");
You have to be very careful that the data you're copying is no bigger than the allocated space. (No, `strncpy() is not the answer to this problem.)
void main() is incorrect; it should be int main(void). If your textbook told you to use void main() find a better textbook; its author doesn't know C very well.
And you need appropriate #include directives for any library functions you're using: <stdio.h> for printf(), <stdlib.h> for exit() and malloc(), and <string.h> for strcpy(). The documentation for each function should tell you which header to include.
I know this is a lot to absorb; don't expect to understand it all right away.
I mentioned the comp.lang.c FAQ; it's an excellent resource, particularly section 6, which discusses arrays and pointers and the often confusing relationship between them.
As for your question 3, how to return a string from a C function, that turns out to be surprisingly complicated because of the way C does memory allocation (basically it leaves to to manage it yourself). You can't safely return a pointer to a local variable, because the variable ceases to exist when the function returns, leaving the caller with a dangling pointer, so returning your str2 is dangerous. Returning a string literal is ok, since that corresponds to an anonymous array that exists for the entire execution of your program. You can declare an array with static and return a pointer to it, or you can use malloc() (which is the most flexible approach, but it means the caller needs to free() the memory), or you can require the caller to pass in a pointer to a buffer into which your function will copy the result.
Some languages let you build a string value and simply return it from a function. C, as you're now discovering, is not one of those languages.
char* str1="string";
This creates a pointer to a literal string that will be located on either .data or .text segments and is accessible at all times. Whenever you do something like that, be sure to declare it const, because if you try to modify it, nasty things might happen.
char str2[7]="string";
This creates a local buffer on the stack with a copy of the literal string. It becomes unavailable once the function returns. That explains the weird result you're getting.
char* str3=(char)malloc(sizeof(char)*7);
This creates a buffer on the heap (uninitialized) that will be available until you free it. And free it you must, or you will get a memory leak.
The string literal "string" is stored as a 7-element array of char with static extent, meaning that the memory for it is allocated at program startup and held until the program terminates.
The declaration
char *str1 = "string";
assigns the address of the string literal to str1. Even though the variable str1 ceases to exist when the function exits, its value (the address of the literal "string") is still valid outside of the function.
The declaration
char str2[7] = "string";
declares str2 as an array of char, and copies the contents of the string literal to it. When the function exits, str2 ceases to exist, and its contents are no longer meaningful.
The declaration
char *str3 = (char*) malloc(sizeof(char) * 7);
which can be simplified to
char *str3 = malloc(sizeof *str3 * 7);
allocates an uninitialized 7-byte block of memory and copies its address to str3. When the function exits, the variable str3 ceases to exist, but the memory it points to is still allocated. As written, this is a memory leak, because you don't preserve the value of the pointer in the calling code. Note that, since you don't copy anything to this block, the output in main will be random.
Also, unless your compiler documentation explicitly lists void main() as a legal signature for the main function, use int main(void) instead.
No guides I've seen seem to explain this very well.
I mean, you can allocate memory for a char*, or write char[25] instead? What's the difference? And then there are literals, which can't be manipulated? What if you want to assign a fixed string to a variable? Like, stringVariable = "thisIsALiteral", then how do you manipulate it afterwards?
Can someone set the record straight here? And in the last case, with the literal, how do you take care of null-termination? I find this very confusing.
EDIT: The real problem seems to be that as I understand it, you have to juggle these different constructs in order to accomplish even simple things. For instance, only char * can be passed as an argument or return value, but only char[] can be assigned a literal and modified. I feel like it's obvious that we frequently/always needs to be able to do both, and that's where my pitfall is.
What is the difference between an allocated char* and char[25]?
The lifetime of a malloc-ed string is not limited by the scope of its declaration. In plain language, you can return malloc-ed string from a function; you cannot do the same with char[25] allocated in the automatic storage, because its memory will be reclaimed upon return from the function.
Can literals be manipulated?
String literals cannot be manipulated in place, because they are allocated in read-only storage. You need to copy them into a modifiable space, such as static, automatic, or dynamic one, in order to manipulate them. This cannot be done:
char *str = "hello";
str[0] = 'H'; // <<== WRONG! This is undefined behavior.
This will work:
char str[] = "hello";
str[0] = 'H'; // <<=== This is OK
This works too:
char *str = malloc(6);
strcpy(str, "hello");
str[0] = 'H'; // <<=== This is OK too
How do you take care of null termination of string literals?
C compiler takes care of null termination for you: all string literals have an extra character at the end, filled with \0.
Your question refers to three different constructs in C: char arrays, char pointers allocated on the heap, and string literals. These are all different is subtle ways.
Char arrays, which you get by declaring char foo[25] inside a function, that memory is allocated on the stack, it exists only within the scope you declared it, but exactly 25 bytes have been allocated for you. You may store whatever you want in those bytes, but if you want a string, don't forget to use the last byte to null-terminate it.
Character pointers defined with char *bar only hold a pointer to some unallocated memory. To make use of them you need to point them to something, either an array as before (bar = foo) or allocate space bar = malloc(sizeof(char) * 25);. If you do the latter, you should eventually free the space.
String literals behave differently depending on how you use them. If you use them to initialize a char array char s[] = "String"; then you're simply declaring an array large enough to exactly hold that string (and the null terminator) and putting that string there. It's the same as declaring a char array and then filling it up.
On the other hand, if you assign a string literal to a char * then the pointer is pointing to memory you are not supposed to modify. Attempting to modify it may or may not crash, and leads to undefined behavior, which means you shouldn't do it.
Since other aspects are answered already, i would only add to the question "what if you want the flexibility of function passing using char * but modifiability of char []"
You can allocate an array and pass the same array to a function as char *. This is called pass by reference and internally only passes the address of actual array (precisely address of first element) instead of copying the whole. The other effect is that any change made inside the function modifies the original array.
void fun(char *a) {
a[0] = 'y'; // changes hello to yello
}
main() {
char arr[6] = "hello"; // Note that its not char * arr
fun(arr); // arr now contains yello
}
The same could have been done for an array allocated with malloc
char * arr = malloc(6);
strcpy(arr, "hello");
fun(arr); // note that fun remains same.
Latter you can free the malloc memory
free(arr);
char * a, is just a pointer that can store address, which might be of a single variable or might be the first element of an array. Be ware, we have to assign to this pointer before actually using it.
Contrary to that char arr[SIZE] creates an array on the stack i.e. it also allocates SIZE bytes. So you can directly access arr[3] (assuming 3 is less than SIZE) without any issues.
Now it makes sense to allow assigning any address to a, but not allowing this for arr, since there is no other way except using arr to access its memory.
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.
I'm learning C right now and got a bit confused with character arrays - strings.
char name[15]="Fortran";
No problem with this - its an array that can hold (up to?) 15 chars
char name[]="Fortran";
C counts the number of characters for me so I don't have to - neat!
char* name;
Okay. What now? All I know is that this can hold an big number of characters that are assigned later (e.g.: via user input), but
Why do they call this a char pointer? I know of pointers as references to variables
Is this an "excuse"? Does this find any other use than in char*?
What is this actually? Is it a pointer? How do you use it correctly?
thanks in advance,
lamas
I think this can be explained this way, since a picture is worth a thousand words...
We'll start off with char name[] = "Fortran", which is an array of chars, the length is known at compile time, 7 to be exact, right? Wrong! it is 8, since a '\0' is a nul terminating character, all strings have to have that.
char name[] = "Fortran";
+======+ +-+-+-+-+-+-+-+--+
|0x1234| |F|o|r|t|r|a|n|\0|
+======+ +-+-+-+-+-+-+-+--+
At link time, the compiler and linker gave the symbol name a memory address of 0x1234.
Using the subscript operator, i.e. name[1] for example, the compiler knows how to calculate where in memory is the character at offset, 0x1234 + 1 = 0x1235, and it is indeed 'o'. That is simple enough, furthermore, with the ANSI C standard, the size of a char data type is 1 byte, which can explain how the runtime can obtain the value of this semantic name[cnt++], assuming cnt is an integer and has a value of 3 for example, the runtime steps up by one automatically, and counting from zero, the value of the offset is 't'. This is simple so far so good.
What happens if name[12] was executed? Well, the code will either crash, or you will get garbage, since the boundary of the array is from index/offset 0 (0x1234) up to 8 (0x123B). Anything after that does not belong to name variable, that would be called a buffer overflow!
The address of name in memory is 0x1234, as in the example, if you were to do this:
printf("The address of name is %p\n", &name);
Output would be:
The address of name is 0x00001234
For the sake of brevity and keeping with the example, the memory addresses are 32bit, hence you see the extra 0's. Fair enough? Right, let's move on.
Now on to pointers...
char *name is a pointer to type of char....
Edit:
And we initialize it to NULL as shown Thanks Dan for pointing out the little error...
char *name = (char*)NULL;
+======+ +======+
|0x5678| -> |0x0000| -> NULL
+======+ +======+
At compile/link time, the name does not point to anything, but has a compile/link time address for the symbol name (0x5678), in fact it is NULL, the pointer address of name is unknown hence 0x0000.
Now, remember, this is crucial, the address of the symbol is known at compile/link time, but the pointer address is unknown, when dealing with pointers of any type
Suppose we do this:
name = (char *)malloc((20 * sizeof(char)) + 1);
strcpy(name, "Fortran");
We called malloc to allocate a memory block for 20 bytes, no, it is not 21, the reason I added 1 on to the size is for the '\0' nul terminating character. Suppose at runtime, the address given was 0x9876,
char *name;
+======+ +======+ +-+-+-+-+-+-+-+--+
|0x5678| -> |0x9876| -> |F|o|r|t|r|a|n|\0|
+======+ +======+ +-+-+-+-+-+-+-+--+
So when you do this:
printf("The address of name is %p\n", name);
printf("The address of name is %p\n", &name);
Output would be:
The address of name is 0x00005678
The address of name is 0x00009876
Now, this is where the illusion that 'arrays and pointers are the same comes into play here'
When we do this:
char ch = name[1];
What happens at runtime is this:
The address of symbol name is looked up
Fetch the memory address of that symbol, i.e. 0x5678.
At that address, contains another address, a pointer address to memory and fetch it, i.e. 0x9876
Get the offset based on the subscript value of 1 and add it onto the pointer address, i.e. 0x9877 to retrieve the value at that memory address, i.e. 'o' and is assigned to ch.
That above is crucial to understanding this distinction, the difference between arrays and pointers is how the runtime fetches the data, with pointers, there is an extra indirection of fetching.
Remember, an array of type T will always decay into a pointer of the first element of type T.
When we do this:
char ch = *(name + 5);
The address of symbol name is looked up
Fetch the memory address of that symbol, i.e. 0x5678.
At that address, contains another address, a pointer address to memory and fetch it, i.e. 0x9876
Get the offset based on the value of 5 and add it onto the pointer address, i.e. 0x987A to retrieve the value at that memory address, i.e. 'r' and is assigned to ch.
Incidentally, you can also do that to the array of chars also...
Further more, by using subscript operators in the context of an array i.e. char name[] = "..."; and name[subscript_value] is really the same as *(name + subscript_value).
i.e.
name[3] is the same as *(name + 3)
And since the expression *(name + subscript_value) is commutative, that is in the reverse,
*(subscript_value + name) is the same as *(name + subscript_value)
Hence, this explains why in one of the answers above you can write it like this (despite it, the practice is not recommended even though it is quite legitimate!)
3[name]
Ok, how do I get the value of the pointer?
That is what the * is used for,
Suppose the pointer name has that pointer memory address of 0x9878, again, referring to the above example, this is how it is achieved:
char ch = *name;
This means, obtain the value that is pointed to by the memory address of 0x9878, now ch will have the value of 'r'. This is called dereferencing. We just dereferenced a name pointer to obtain the value and assign it to ch.
Also, the compiler knows that a sizeof(char) is 1, hence you can do pointer increment/decrement operations like this
*name++;
*name--;
The pointer automatically steps up/down as a result by one.
When we do this, assuming the pointer memory address of 0x9878:
char ch = *name++;
What is the value of *name and what is the address, the answer is, the *name will now contain 't' and assign it to ch, and the pointer memory address is 0x9879.
This where you have to be careful also, in the same principle and spirit as to what was stated earlier in relation to the memory boundaries in the very first part (see 'What happens if name[12] was executed' in the above) the results will be the same, i.e. code crashes and burns!
Now, what happens if we deallocate the block of memory pointed to by name by calling the C function free with name as the parameter, i.e. free(name):
+======+ +======+
|0x5678| -> |0x0000| -> NULL
+======+ +======+
Yes, the block of memory is freed up and handed back to the runtime environment for use by another upcoming code execution of malloc.
Now, this is where the common notation of Segmentation fault comes into play, since name does not point to anything, what happens when we dereference it i.e.
char ch = *name;
Yes, the code will crash and burn with a 'Segmentation fault', this is common under Unix/Linux. Under windows, a dialog box will appear along the lines of 'Unrecoverable error' or 'An error has occurred with the application, do you wish to send the report to Microsoft?'....if the pointer has not been mallocd and any attempt to dereference it, is guaranteed to crash and burn.
Also: remember this, for every malloc there is a corresponding free, if there is no corresponding free, you have a memory leak in which memory is allocated but not freed up.
And there you have it, that is how pointers work and how arrays are different to pointers, if you are reading a textbook that says they are the same, tear out that page and rip it up! :)
I hope this is of help to you in understanding pointers.
That is a pointer. Which means it is a variable that holds an address in memory. It "points" to another variable.
It actually cannot - by itself - hold large amounts of characters. By itself, it can hold only one address in memory. If you assign characters to it at creation it will allocate space for those characters, and then point to that address. You can do it like this:
char* name = "Mr. Anderson";
That is actually pretty much the same as this:
char name[] = "Mr. Anderson";
The place where character pointers come in handy is dynamic memory. You can assign a string of any length to a char pointer at any time in the program by doing something like this:
char *name;
name = malloc(256*sizeof(char));
strcpy(name, "This is less than 256 characters, so this is fine.");
Alternately, you can assign to it using the strdup() function, like this:
char *name;
name = strdup("This can be as long or short as I want. The function will allocate enough space for the string and assign return a pointer to it. Which then gets assigned to name");
If you use a character pointer this way - and assign memory to it, you have to free the memory contained in name before reassigning it. Like this:
if(name)
free(name);
name = 0;
Make sure to check that name is, in fact, a valid point before trying to free its memory. That's what the if statement does.
The reason you see character pointers get used a whole lot in C is because they allow you to reassign the string with a string of a different size. Static character arrays don't do that. They're also easier to pass around.
Also, character pointers are handy because they can be used to point to different statically allocated character arrays. Like this:
char *name;
char joe[] = "joe";
char bob[] = "bob";
name = joe;
printf("%s", name);
name = bob;
printf("%s", name);
This is what often happens when you pass a statically allocated array to a function taking a character pointer. For instance:
void strcpy(char *str1, char *str2);
If you then pass that:
char buffer[256];
strcpy(buffer, "This is a string, less than 256 characters.");
It will manipulate both of those through str1 and str2 which are just pointers that point to where buffer and the string literal are stored in memory.
Something to keep in mind when working in a function. If you have a function that returns a character pointer, don't return a pointer to a static character array allocated in the function. It will go out of scope and you'll have issues. Repeat, don't do this:
char *myFunc() {
char myBuf[64];
strcpy(myBuf, "hi");
return myBuf;
}
That won't work. You have to use a pointer and allocate memory (like shown earlier) in that case. The memory allocated will persist then, even when you pass out of the functions scope. Just don't forget to free it as previously mentioned.
This ended up a bit more encyclopedic than I'd intended, hope its helpful.
Editted to remove C++ code. I mix the two so often, I sometimes forget.
char* name is just a pointer. Somewhere along the line memory has to be allocated and the address of that memory stored in name.
It could point to a single byte of memory and be a "true" pointer to a single char.
It could point to a contiguous area of memory which holds a number of characters.
If those characters happen to end with a null terminator, low and behold you have a pointer to a string.
char *name, on it's own, can't hold any characters. This is important.
char *name just declares that name is a pointer (that is, a variable whose value is an address) that will be used to store the address of one or more characters at some point later in the program. It does not, however, allocate any space in memory to actually hold those characters, nor does it guarantee that name even contains a valid address. In the same way, if you have a declaration like int number there is no way to know what the value of number is until you explicitly set it.
Just like after declaring the value of an integer, you might later set its value (number = 42), after declaring a pointer to char, you might later set its value to be a valid memory address that contains a character -- or sequence of characters -- that you are interested in.
It is confusing indeed. The important thing to understand and distinguish is that char name[] declares array and char* name declares pointer. The two are different animals.
However, array in C can be implicitly converted to pointer to its first element. This gives you ability to perform pointer arithmetic and iterate through array elements (it does not matter elements of what type, char or not). As #which mentioned, you can use both, indexing operator or pointer arithmetic to access array elements. In fact, indexing operator is just a syntactic sugar (another representation of the same expression) for pointer arithmetic.
It is important to distinguish difference between array and pointer to first element of array. It is possible to query size of array declared as char name[15] using sizeof operator:
char name[15] = { 0 };
size_t s = sizeof(name);
assert(s == 15);
but if you apply sizeof to char* name you will get size of pointer on your platform (i.e. 4 bytes):
char* name = 0;
size_t s = sizeof(name);
assert(s == 4); // assuming pointer is 4-bytes long on your compiler/machine
Also, the two forms of definitions of arrays of char elements are equivalent:
char letters1[5] = { 'a', 'b', 'c', 'd', '\0' };
char letters2[5] = "abcd"; /* 5th element implicitly gets value of 0 */
The dual nature of arrays, the implicit conversion of array to pointer to its first element, in C (and also C++) language, pointer can be used as iterator to walk through array elements:
/ *skip to 'd' letter */
char* it = letters1;
for (int i = 0; i < 3; i++)
it++;
In C a string is actually just an array of characters, as you can see by the definition. However, superficially, any array is just a pointer to its first element, see below for the subtle intricacies. There is no range checking in C, the range you supply in the variable declaration has only meaning for the memory allocation for the variable.
a[x] is the same as *(a + x), i.e. dereference of the pointer a incremented by x.
if you used the following:
char foo[] = "foobar";
char bar = *foo;
bar will be set to 'f'
To stave of confusion and avoid misleading people, some extra words on the more intricate difference between pointers and arrays, thanks avakar:
In some cases a pointer is actually semantically different from an array, a (non-exhaustive) list of examples:
//sizeof
sizeof(char*) != sizeof(char[10])
//lvalues
char foo[] = "foobar";
char bar[] = "baz";
char* p;
foo = bar; // compile error, array is not an lvalue
p = bar; //just fine p now points to the array contents of bar
// multidimensional arrays
int baz[2][2];
int* q = baz; //compile error, multidimensional arrays can not decay into pointer
int* r = baz[0]; //just fine, r now points to the first element of the first "row" of baz
int x = baz[1][1];
int y = r[1][1]; //compile error, don't know dimensions of array, so subscripting is not possible
int z = r[1]: //just fine, z now holds the second element of the first "row" of baz
And finally a fun bit of trivia; since a[x] is equivalent to *(a + x) you can actually use e.g. '3[a]' to access the fourth element of array a. I.e. the following is perfectly legal code, and will print 'b' the fourth character of string foo.
#include <stdio.h>
int main(int argc, char** argv) {
char foo[] = "foobar";
printf("%c\n", 3[foo]);
return 0;
}
One is an actual array object and the other is a reference or pointer to such an array object.
The thing that can be confusing is that both have the address of the first character in them, but only because one address is the first character and the other address is a word in memory that contains the address of the character.
The difference can be seen in the value of &name. In the first two cases it is the same value as just name, but in the third case it is a different type called pointer to pointer to char, or **char, and it is the address of the pointer itself. That is, it is a double-indirect pointer.
#include <stdio.h>
char name1[] = "fortran";
char *name2 = "fortran";
int main(void) {
printf("%lx\n%lx %s\n", (long)name1, (long)&name1, name1);
printf("%lx\n%lx %s\n", (long)name2, (long)&name2, name2);
return 0;
}
Ross-Harveys-MacBook-Pro:so ross$ ./a.out
100001068
100001068 fortran
100000f58
100001070 fortran