#include <stdio.h>
const int MAX = 4
int main () {
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %s\n", i, names[i] );
}
return 0;
}
Why can one just print names[i] instead of *names[i]? Could someone provide a memory diagram for clarification?
Format specifier %s requires a parameter of type (char*), i.e. a pointer to an array of chars.
In char* names[], each element is such a pointer to an array of chars; after your initialisation, names[0] holds a memory address pointing to the begin of string literal "Zara Ali". Thus, it is correct to pass such a pointer as argument to printf("%s", ...).
However, if you write *names[0], then you actually dereference this pointer, yielding a char-value, which is in this case 'Z'. This is just as if you wrote printf("%s", 'Z'), such that expected data type char* and actual data type char do not match and yield compiler warnings and - when ignoring them -undefined behaviour.
I don't think a memory diagram is necessary.
Anything in c with * is a pointer in memory.
So,
int *a = 3;
a = 3;
*a = memory address
printf("result = %d, result 2 =%d\n", a, *a);
output:
result = 3, result 2 = 9023923 (this is a random memory address)
You must memorize this!
char is a single 8bit character, we represent strings in c by having an array of char's of unknown length are using the address of the first char, so for a single string we use
char * name
Meaning name contains the memory address (pointers) of the first character, we can get to the second char by just increamenting the memory address, name+1.
If we want an array of strings what we actually do is have and array of memory addresses (pointers) to multiple strings, So
char * names[] = ...
is an array of pointers to the first char of a string, you have to specify the number of elements in the c array but because you have supplied it with values, the compiler can infer the number of elements for you.
Each string you point to with each element in names can be located anywhere in memory, its just an array of memory addresses, names[0] could be equal to 10000 and names[1] could be equal to 10, meaning string 0 starts at address 10000 and string 1 starts at address 10, but because the way you have declared it the compiler will most likely have them in memory in order one after the other, but you could later on assign a different memory address to any one of the values.
names[2] = "New Values";
and the value of names[2] will then be the a different location in memory where "New Values" exists and the original string, "Nuha Ali", will still be located in memory at its original location untouched.
If you wanted you could created a char array like so
char names[] = "Zara Ali\0Hina Ali\0...
then names will be created long enough to contain the entire string and the string will be copied into the array instead of the first char memory addresses of each string being copied into the array. names will then just point to a single array of chars and names[1] will return you the second character, and you will not be able to determine where the strings end, any str function will assume the string terminates with the first '\0'.
(Note: your compiler may not let you actually put a string terminator '\0' mid string, I haven't tried it, though I think it should be legal if its not, but you get the idea of how the memory can be layout).
That is because the * is included in the [].
Have a look at Array subscripting:
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))
Related
I was solving a challenge on CodeSignal in C. Even though the correct libraries where included, I couldn't use the strrev function in the IDE, so I looked up a similar solution and modified it to work. This is good. However, I don't understand the distinction between a literal string and an array. Reading all this online has left me a bit confused. If C stores all strings as an array with each character terminated by \0 (null terminated), how can there be any such thing as a literal string? Also if it is the case that strings are stored as an array, *would inputString store the address of the array or is it an array itself of all the individual characters stored.
Thanks in advance for any clarification provided!
Here is the original challenge, C:
Given the string, check if it is a palindrome.
bool solution(char * inputString) {
// The input will be character array type, storing a single character each terminated by \0 at each index
// * inputString is a pointer that stores the memory address of inputString. The memory address points to the user inputted string
// bonus: inputString is an array object starting at index 0
// The solution function is set up as a Boolean type ("1" is TRUE and the default "0" is FALSE)
int begin;
// The first element of the inputString array is at position 0, so is the 'counter'
int end = strlen(inputString) - 1;
// The last element is the length of the string minus 1 since the counter starts at 0 (not 1) by convention
while (end > begin) {
if (inputString[begin++] != inputString[end--]) {
return 0;
}
} return 1;
}
A string is also an array of symbols. I think that what you don't understand is the difference between a char pointer and a string. Let me explain in an example:
Imagine I have the following:
char str[20]="helloword";
str is the address of the first symbol of the array. In this case str is the address of h. Now try to printf the following:
printf("%c",str[0]);
You can see that it has printed the element of the addres that is 'h'.
If now I declare a char pointer, it will be poining to whatever char adress I want:
char *c_pointer = str+1;
Now print the element of c_pointer:
printf("%c",c_pointer[0]);
You can see that it will print 'e' as it is the element of the second adress of the original string str.
In addition, what printf("%s", string) does is to printf every elemet/symbol/char from the starting adress(string) to the end adress where its element is '\0'.
The linked question/answers in the comments pretty much cover this, but saying the same thing a slightly different way helps sometimes.
A string literal is a quoted string assigned to a char pointer. It is considered read only. That is, any attempts to modify it result in undefined behavior. I believe that most implementations put string literals in read-only memory. IMO, it's a shortcoming of C (fixed in C++) that a const char* type isn't required for assigning a string literal. Consider:
int main(void)
{
char* str = "hello";
}
str is a string literal. If you try to modify this like:
#include <string.h>
...
str[2] = 'f'; // BAD, undefined behavior
strcpy(str, "foo"); // BAD, undefined behavior
you're broken the rules. String literals are read only. In fact, you should get in the habit of assigning them to const char* types so the compiler can warn you if you try to do something stupid:
const char* str = "hello"; // now you should get some compiler help if you
// ever try to write to str
In memory, the string "hello" resides somewhere in memory, and str points to it:
str
|
|
+-------------------> "hello"
If you assign a string to an array, things are different:
int main(void)
{
char str2[] = "hello";
}
str2 is not read only, you are free to modify it as you want. Just take care not to exceed the buffer size:
#include <string.h>
...
str2[2] = 'f'; // this is OK
strcpy(str2, "foo"); // this is OK
strcpy(str2, "longer than hello"); // this is _not_ OK, we've overflowed the buffer
In memory, str2 is an array
str2 = { 'h', 'e', 'l', 'l', '0', '\0' }
and is present right there in automatic storage. It doesn't point to some string elsewhere in memory.
In most cases, str2 can be used as a char* because in C, in most contexts, an array will decay to a pointer to it's first element. So, you can pass str2 to a function with a char* argument. One instance where this is not true is with sizeof:
sizeof(str) // this is the size of pointer (either 4 or 8 depending on your
// architecture). If _does not matter_ how long the string that
// str points to is
sizeof(str2) // this is 6, string length plus the NUL terminator.
char mening[] = "tjena pa dig hog";
This string contains 16 characters. I am then using a function adresss() to find the memory address of a random character in that array. The function adresss() returns a pointer containing the address. The address is at this moment 0x7ffeefbff5f9.
I now need to know what positions that address is pointing to, example is it pointing to the "t" at position 0 in the array, or maybe it is pointing to "d" at position 9. How do I do this?
Edit:
char* adresss(char mening[]){
//Lots of code going on here
return &mening[i];
}
int main(void){
char mening[] = "tjena pa dig hog";
char* ptr;
ptr = adresss(mening);
printf("%p\n", ptr);
That is basically how I get the memory adress. I want to know what "i" was, inside the main function only knowing the memory adress.
If you have two pointers, both pointing to the same array (or to one beyond the end of the array), then you can subtract them from each other.
For example:
char mening[] = "tjena pa dig hog";
char *pointer_to_mening = &mening[10]; // Pointer to the eleventh character
// Should print 10 (which is the index of the eleventh character)
printf("The distance is %zu\n", pointer_to_mening - mening);
I am first concatenating a series of elements in an auxiliary char array to then assign the concatenated array to the pointer. The problem comes when assigning this char array to the pointer, where it produces a segmentation fault.
My approach was the following one:
char aux_name [12];
char * name = (char *) malloc(sizeof(char)*13);
int i;
for(i = 0; i < 5; i++){
sprintf(aux_name, "id_%i", i);
*name = (void *) (intptr_t) aux_name; //Conflict line
//Do something with variable name (it is required a pointer)
}
You don't assign a pointer value to an already malloc()-ed pointer, you'll be facing memory-leak there. You have to use strcpy() to achieve what you want.
OTOH, if you don't allocate memory dynamically, then you can assign the pointer like
name = aux_name;
That said,
I am first concatenating a series of elements in an auxiliary char array
Well, you're not. you're simply overwriting the array every time in every iteration. What you need to do is
Collect the return value of sprintf() every time.
next iteration, advance the pointer to buffer by that many locations to concatinate the new input after the previous one.
Note / Suggestion:
do not cast the return value of malloc() and family in C.
sizeof(char) is guranteed to be 1 in c standard. You don't need to use that, simply drop that part.
You can't do that, and you don't really need to, this would work
size_t nonConstanSizeInBytes = 14;
char *name = malloc(nonConstanSizeInBytes);
snprintf(name, 13, "id_%i", i);
In some code that I read, there was an initializing statement like this
char *array[]= { "something1", "something2", "something3" };
What does this mean, and what does that pointer actually point to?
How is that allocated in memory, and how can I access every element and every character of an element in that array ?
--- Edited ---
and please what is the difference in this example between
char array[3];
and
char *array[3];
--- Edited ---
what that means ?
It's initializing an array of strings (char *) with three values (three pointers to null-terminating strings)
and what that pointer points to ?
It should point to the first element in the char* array
how is that allocated in memory ?
It will allocate enough memory to store the three strings followed by null-terminators, as well as the three pointers to those strings:
array --> pointer to three sequential memory addresses
array[0] --> something1{\0}
array[1] --> something2{\0}
array[2] --> something3{\0}
Note that the strings may not necessarily be in sequential memory
and how can I access every element
if by "element" you mean the string, you can loop though the pointers:
for(int i=0; i<3; i++)
{
char* element = array[i];
}
and every character of an element in that array
well, you could access the chars using array syntax (element[i]) but I would recommend using the C string functions for safety (so you don't have to worry about accessing memory outside the range of the string)
This is a way to initialize an array at the same time that you create it.
This code
char *array[]= { "a", "b", "c" };
will have the same result as this code.
char *array[3];
array[0] = "a";
array[1] = "b";
array[2] = "c";
Here is a good source for more information.
http://www.iu.hio.no/~mark/CTutorial/CTutorial.html#Strings
EDIT:
char array[3]; is an array of 3 char.
char *array[3]; is an array of 3 pointers to char.
char * in C is a string.
array is the name of the variable being declared.
[] indicates that it is an array.
{ "something1", "something2", "something3" } is initializing the contents of the array.
Accessing elements is done like so:
array[0] gives the 1st element - "something1".
array[1] gives the 2nd element - "something2".
etc.
Note:
As was pointed out in the comments, char * isn't technically a string.
It's a pointer to a char. You can visualize a string in memory like so:
<-------------------------->
..134|135|136|137|138|139|..
<-------------------------->
'H'|'e'|'l'|'l'|'o'|'\0'
<-------------------------->
This block of memory (locations 134-139) is holding the string of characters.
For example:
array[0] actually returns a pointer to the first character in "something1".
You use the fact that the characters are sequentially in memory to access the rest of the string in various ways:
/* ch points to the 's' */
char* ch = array[0];
/* ch2 points to the 'e' */
char* ch2 = ch + 3;
/* ch3 == 'e' */
char ch3 = *ch2;
/* ch4 == 'e' */
char ch4 = *(ch + 3);
/* ch5 == 'e' */
char ch5 = ch[3];
This defines a array of char pointers (aka. "c strings").
For accessing the content you could do:
for (int i=0; i<sizeof(array)/sizeof(char*); i++) {
printf("%s", array[i]);
}
It declares array as an array of 3 pointers to char, with its 3 elements initialized to pointers to the respective strings. The memory is allocated for the array itself (3 pointers) and for the strings. The strings memory is allocated statically. The array's memory is allocated either statically (if the declaration is outside of all functions) or dynamically (typically, on the execution stack of the CPU) if the declaration is inside a function.
So basically strcpy assigns the address of the 2nd argument to the 1st, but how does it do it with an array as the first argument? like in my program, i tried changing the address of the array but unfortunately it wont compile. So I had to resort to making a character pointer variable to assign the return value of capitalize. Is there something I'm misunderstanding?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char string[20];
char *Capitalize(char *str)
{
int i;
char *temp;
temp = malloc(sizeof(char)*(int)(strlen(str)+1));
for(i = 0;i < strlen(str);i++)
{
if(*(str+i) >= 'a' && *(str+i)<= 'z')
*(temp+i) = *(str+i) - 32;
else
*(temp+i) = *(str+i);
}
*(temp+i) = '\0';
return temp;
}
int main(void)
{
string word;
printf("Enter word to capitalize: ");
scanf("%19s",word);
word = Capitalize(word);
printf("%s",word);
return 0;
}
strcpy() makes a copy, just like the name implies. it's perfectly legal to copy a string in to an array.
When you make an initialization of an array such as:
char myarr[] = "hello";
You're actually copying the characters into the array.
You seem to be confusing arrays with pointers (see here for some reason you can't treat them the same)
In C, qualifying an array by name without an indexer, is equivalent to specifying a pointer to the memory address of the first element in the array, that is why you can pass as a parameter an array to functions like strcpy.
char * strcpy ( char * destination, const char * source );
strcpy will copy whatever series of characters are found, starting at memory address specified by source, to the memory address specified by destination, until a null character (0) is found (this null character is also copied to the destination buffer).
The address values specified in the parameters are not modified, they just specify from where in memory to copy and where to. It is important that destination is pointing to a memory buffer (can be a char array or a block of memory requested via malloc) with enough capacity for the copied string to fit, otherwise a buffer underrun will occur (you will write characters past the end of your buffer) and your program might crash or behave in a weird way.
Hope I have been clear and not confused you more with my explanation ;)
The thing you seem to be missing is that in c/c++ strings ARE arrays, in most practical respects declaring
char c[] = "hello";
and
char* c = "hello";
is the same thing, all strcpy does is copy the characters into the destination memory, whether that memory is allocated as an array (presumably on the stack) or pointer (presumably on the heap);it does not make a difference.