0

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;
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • 1
    "each character terminated by \0" - this is incorrect. \0 is stored after the _last_ character, so e.g. "foo" is stored as an array `[ 'f', 'o', 'o', '\0']`, and in your case `inputString` stores the address of the first character. – tromgy Dec 22 '22 at 14:33
  • 1
    This post may clarify things for you: https://stackoverflow.com/questions/10186765/what-is-the-difference-between-char-array-and-char-pointer-in-c?rq=1 – Anthony Kelly Dec 22 '22 at 14:37

2 Answers2

0

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'.

sacacorchos
  • 163
  • 9
  • "str is the address of the first symbol of the array" No, `str` *is* the array. There are just a lot of cases where an array *decays* into a pointer to the first element, such as when passing it as an argument to a function or doing arithmetic on it. There are also cases where it doesn't. `sizeof(str)` is 20, not the size of a pointer. And `&str` is a `char (*)[20]` (a pointer to an char array of length 20), not a `char**` – Kevin Dec 22 '22 at 15:56
  • you are right that sizeof(char) is not the size of a pointer as it is the size of the array (in that context str is not the adress of the first element of teh array okay). But, if I make: char **a = &str , what is the problem of that? I mean &str is not a pointer to a char pointer? – sacacorchos Dec 22 '22 at 16:12
  • The problem comes if you try to assign to `*a`. With a valid assignment, it's fine: `char *s = "hello"; char **a = &s; *a = "world";` (`s` now points to the string `"world"`). But if `a` actually points to an array, not a `char*`, things go wrong: https://godbolt.org/z/K86sKx7a6 (also note the compiler warning about the incompatible assignment) – Kevin Dec 22 '22 at 16:26
  • I think that a better definition would have been: "str is the array and it is pointing to the first element of the array, &str is the adress of the array (it can be a char** or a char(*)[SIZE] depending on the case" ) . Sounds better now? – sacacorchos Dec 24 '22 at 16:22
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.
yano
  • 4,827
  • 2
  • 23
  • 35