Identification: Is that a string? - c

I dont know if that a string or an array...
char str4[100] = { 0 };
That code is a string?
If yes what it printing?

I dont know if that a string or an array...
It is definitely an array. It can also be a string since a string is an array of characters terminated by a null character in C.
You can use it as an array:
char str4[100] = { 0 };
str4[0] = 'a';
You can also use it as a string:
if ( strcmp(str4, "ABC") == 0 )
{
// This string contains "ABC"
}
When an array of characters is not a string
You can create an array of characters that cannot be used like a string.
char str[4] = { 'a', 'b', 'c', 'd' };
if ( str[0] == 'a' ) // OK
{
// Do something
}
if ( strcmp(str, "ABC") == 0 ) // Problem. str does not have a null character.
// It cannot be used like a string.
{
}

str4 is an array of char's, so yes: it can be a string. You're initializing it to {0}. This means the first element in the array is being initialized to a terminating nul character (the end of a string), the result being: str4 is a valid, albeit empty, string. Implicitly, the rest of the array will be initialized to 0, too BTW.
Printing this string is the same as printing an empty string:
printf("");
The code you posted is exactly the same as this:
char str4[100] = "";
//or this
char str4[100] = {0, 0, '\0'};//'\0' is the same as 0
//or even
char str4[] = {0, 0, ..., 0};//100 0's is just a pain to write...
Or, in case of a global variable:
char str4[100];
simply because objects that have static storage are initialized to their nul-values (integer compatible types are initialized to 0, pointers to NULL):
If an object that has static storage duration is not initialized explicitly, it is initialized implicitly as if every member that has arithmetic type were assigned 0 and every member that has pointer type were assigned a null pointer constant.
Either way, the short answer is: str4 is an empty string.

By definition in C a string is a contiguous sequence of characters terminated by and including the first null character. So here you array also represents a string of length 0.

In C a string is just an array of bytes that follows a particular convention, namely that the array of bytes be terminated by a null character. In this case, if you try to print str4 with something like printf, you'll find it looks like an empty string because the first byte is a null character, terminating it immediately.

Related

In this solution, if *inputString is a memory address (and the input is a char type) then does *inputString qualify as an array?

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.

When does a while loop stop when it reads a string in C?

I'm trying to implement the strcpy function by myself. The original strcpy is part of the the string.h library.
char *strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *temp = dest;
while (*src)
{
*dest = *src;
src++;
dest++;
}
return temp;
}
void strcpyTest()
{
char source[20] = "aaaaaa";
char dest1[20] = "bbbbbbbbb";
char desta[10]="abcd";
puts(dest1); // bbbbbbbbb
strcpy(dest1, source);
puts(dest1); // aaaaaa
strcpy(desta, source);
puts(desta); // aaaaaa
strcpy(desta, dest1);
puts(desta); // aaaaaa
strcpy(dest1, desta);
puts(dest1); // aaaaaa
strcpy(source, desta);
puts(source); // aaaaaa
}
As you can see, even the first call for the function with a longer dest than the src gives the right result although, by logic, it should give
aaaaaabb and not aaaaaa:
char source[20] = "aaaaaa";
char dest1[20] = "bbbbbbbbb";
strcpy(dest1, source);
puts(dest1);
/** aaaaaa **/
Why does my function work? I would guess that i'll have to manually add the /0 char in the end of *dest* after the while (*src)` will exit.
I mean the whole point of this while (*src) is to exit when it reaches the end of *src* which is the last char in the string which is /0.
Therefore, I would guess i'll have to add this character to *dest* by myself but the code somehow works and copies the string without the manual addition of /0.
So my question is why and how it still works?
When I create a new array, lets say int *arr or char *arr, of 10, i.e char arr[10] or int arr[10] and I initialize only the 2 first indexes, what happens to the values that inside the rest of the indexes? Does they will be filled with zeros or garbage value or what?
Maybe my code works because it filled with zeros and that's why the while loop stops?
For starters you should select another name instead of strcpy.
Let's consider all the calls of your function step by step.
The variable source is declared like
char source[20] = "aaaa";
This declaration is equivalent to the following declaration
char source[20] =
{
'a', 'a', 'a', 'a', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
};
because according to the C Standard elements of the array that were not explicitly initialized are implicitly initialized by zeroes.
The variable desta is declared like
char desta[10]="abcd";
This declaration is equivalent to the following declaration
char desta[10]= { 'a', 'b', 'c', 'd', '\0', '\0', '\0', '\0', '\0', '\0' };
So the first call
strcpy(desta, source);
just substitute four characters "abcd" for four characters "aaaa". The result array desta will contain a string because nether terminating zero is overwritten.
After this call
strcpy(desta, dest1);
the array desta will contain the string "bbbbbbbbb" because the last zero character of the array desta is not overwritten by this call.
This call
strcpy(dest1, desta);
in fact is not being changed the array dest1.
In this call
strcpy(source, desta);
as all the zero characters of the array source were not overwritten the array will contain a string.
You could get an unpredictable result if you called at first
strcpy(desta, dest1);
and then
strcpy(desta, source);
because your function does not append a terminating zero to the destination array.
Here is a demonstrative program.
#include <stdio.h>
#include <assert.h>
char * my_strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *temp = dest;
while (*src)
{
*dest = *src;
src++;
dest++;
}
return temp;
}
int main(void)
{
char source[20] = "aaaaaa";
char dest1[20] = "bbbbbbbbb";
char desta[10]="abcd";
my_strcpy(desta, dest1);
my_strcpy(desta, source);
puts( desta );
return 0;
}
The program output is
aaaaaabbb
That is the desta contains the string "aaaaaabbb" instead of the string aaaaaa.
The updated function could look the following way
char * strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *temp = dest;
while ( ( *dest++ = *src++ ) );
return temp;
}
Correct that this function will not add a \0 to the end of the dest string. You will need to add a final \0 assignment to dest.
Why does it seem to work as-is?
It "works" because your initialization of dest just happens to place a \0 character at the right point in the string. These cases are honestly "unlucky" as they hide all sorts of problems. Another case where this can happen is if you are running a debug build where memory is automatically set to 0 and therefore the final set bug is hidden.
So my question is why and how it still works?
If you initialize the first 2 values on an array, the rest are considered to be garbage, again exactly as you state. The exception to this would be if the array were "global" or "static". In these cases, the compiler will set them to 0 for you.
Your arrays are padded with zeros, which are equivalent to the null-terminator '\0'. When you initialize an array, any elements not explicitly set will be set the same way as if it were a static variable, which is to say the elements not explicitly initialized will be implicitly initialized to 0. So in this case, your strings just happen to have a null-terminator after you finished your copy because when you initialized the array, all of the values not explicitly set by your initializer were set to 0.
If you copy one a 4-character string into a buffer holding an 8-character string, you'll only see the first 4 characters changed in your destination string while leaving another 4 characters still there before you hit a null-terminator.
From the C11 Standard Working Draft
6.7.9 p21
If there are fewer initializers in a brace-enclosed list than there are elements or members
of an aggregate, or fewer characters in a string literal used to initialize an array of known
size than there are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage duration.
So according to the above passage, because you initialized some elements of the array, the elements that you did not explicitly initialize will be treated the same as if it were a static-storage duration object.
So for the rules for statuc storage duration, we have 6.7.9 p10:
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. If an object that has static or thread storage duration is not initialized
explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules,
and any padding is initialized to zero bits;
— if it is a union, the first named member is initialized (recursively) according to these
rules, and any padding is initialized to zero bits;
The above passage tells us that every member of the aggregate (an array in this case) will be initialized as per the element's rules, and in this case, they are of type char, which is considered an arithmetic type, which the rules states will be initialized to 0.

what exactly happens when I do this assignment

Consider this snippet
char a[]="";
Will a NULL-pointer be assigned to the a character pointer *a?
If not how do I check that the no string has been assigned to a?
Will a NULL pointer be assigned to the a character pointer *a?
There is no character pointer here, but an array a of char.
a will be defined as an array of char and initialised to hold an empty-string, that is a c-string with just carrying the 0-terminator, which is one char.
how do I check that the no string has been assigned to a?
So a will have exactly one element. This element compares equal to '\0', which in turn compares equal to 0.
To test this do
#include <stdio.h> /* for puts() */
#include <string.h> /* for strlen() */
int main(void)
{
char a[] = ""; /* The same as: char a[1] = ""; */
/* Possibility 1: */
if (0 == a[0]) /* alternatively use '\0' == a[0] */
{
puts("a is an empty string.");
}
/* Possibility 2: */
if (0 == strlen(a))
{
puts("a has length zero.");
}
}
a will contain 1 element:
a[0] == '\0'
Note: a is not a pointer.
First of all, a is not a character pointer, it is an array of char. There are some cases where the latter is converted to the former, but they are inherently not the same type.
That said, in this initialization, array a will be initialized with an empty string.
Empty string means, the first element will be the terminating null character, so the easiest way to check if an array contains an empty string is to compare the first element with null, like
if (a[0] == '\0') { /*do the action*/ }
==> Will a NULL-pointer be assigned to the a character pointer *a?
Arrays are not pointers.
For better understanding, lets refer an example from C Standard#6.7.9p32 [emphasis mine]
EXAMPLE 8 The declaration
char s[] = "abc", t[3] = "abc";
defines ''plain'' char array objects s and t whose elements are initialized with character string literals. This declaration is identical to
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
defines p with type ''pointer to char'' and initializes it to point to an object with type ''array of char'' with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
So, this statement
char a[]="";
defines char array object a whose elements are initialized with character string literal "". Note that "" is a string literal containing a single character '\0'.
The above statement is equivalent to
char a[] = {'\0'};
If we omit the dimension, compiler computes it for us based on the size of the initializer (here it will be 1 because initializer is only having one character '\0'). So the statement is same as
char a[1] = {'\0'};

geting each element of a textfile until ':' and store on struct variable

I need help :/
On textfile, I have something like this:
MyName: 15 3
and I want to read each element until ':' and store it in variable name of the struct, and read the next elements and store 15 and 3 in another variables.
typedef struct STRUCT_PLAYER{char name[20];
int sucess;
int numQuest;
int wrongs;} PLAYER;
int readTop(PLAYER playTop[]){
char *classify = "classificacao.txt";
FILE *fl;
fl = fopen(classify, "r");
char c;
int n=0;
if(cl==NULL){
printf("Error reading the file %s\n", classify);
exit(1);
}
else{
while(c!=EOF){
while(c!=':'){
c=getc(fl);
if(c!=':') playTop[n].name=c;
}
if(c==':')fscanf(fl, " %d %d\n", &playTop[n].numQuest, &playTop[n].wrongs);
n++;
}
}
return n;
this is my code, but it appears me an error, on this line
if(c!=':') playerTOP[n].nome=c;
error: assignment to expression with array type
but I don't understand what it is
c is char, playTop->name is a char[], so your are assigning incompatible types. Also
coderredoc answer
Array name is not a modifiable lvalue
When you initialize your structure do:
int n=0;
playTop[n].name[0] = 0;
...
while(c!=':'){
char cs[] = { getc(fl), 0 };
if(c!=':')
strcat(playTop[n].name, cs);
}
With this cs is a C-String containing one letter only and strcat appends
the string to playTop[n].name, thus saving the name
EDIT
Ricardo's comment
thank you. but I din't understant why you put a zero on char cs[] = { getc(fl), 0}
That is what I was talking about in the comment. In C a string must be
'\0'-terminated.
A C-String is a sequence of bytes. This sequence must end with the value 0.
Every value in the sequence represents a character based on the
ASCII encoding, for example the
character 'a' is 97, 'b' is 98, etc. The character '\0' has
the value 0 and it's the character that determines the end of the string.
That's why you hear a lot that C-Strings are '\0'-terminated.
In C you use an array of chars (char string[], char string[SOME VALUE]) to
save a string. For a string of length n, you need an array of dimension n+1, because
you also need one space for the terminating '\0' character.
When dealing with strings, you always have to think about the proper type,
whether your are using an array or a pointer. A pointer
to char doesn't necessarily mean that you are dealing with a C-String!
Let's take a look at
char str1[] = "Hallo";
char str2[] = { 'H', 'a', 'l', 'l', 'o', 0 };
Both declarations do the same thing, they initialized the arrays str1 and
str2 with 6 elements. str1[5] and str2[5] will be the same: 0 (or '\0'
in its char notation).
A string literal is the text that is wrapped in quotes, "Hello" is a string
literal. Somewhere in the memory of the process the linker puts the sequence
'H', 'a', 'l', 'l', 'o', 0 in memory, usually read-only memory (note the 0
at the end). Even though you don't write the '\0' explicitly, it will have
one.
The '\0' at the end of the sequence of chars is what makes the sequence a
C-String, not the type of the variable. If there is no '\0' at the end, it is not a C-String.
char cs[] = { getc(fl), 0};
is a shorthand of
char cs[2];
cs[0] = getc(fl);
cs[1] = '\0';
By doing the last assignments, I ensure that cs holds a C-String. Most
functions defined in string.h (standard library) expect C-Strings, so they
must be '\0'-terminated.
man strcat
#include <string.h>
char *strcat(char *dest, const char *src);
DESCRIPTION
The strcat() function appends the src string to the dest string,
overwriting the terminating null byte ('\0') at the end of dest, and
then adds a terminating null byte.
From the description you'll see that both dest and src must be strings,
thus '\0'-terminated. That's why I said you should initialize
playTop->name[0] with 0, so that is will be a valid (and empty) string. Only
then I can use strcat.
Luckily there are many ways to archive the same results. If you don't want to
use strcat you could do it also this way:
int name_idx = 0;
while(c!=EOF){
while(c!=':'){
c=getc(fl);
if(c!=':') playTop[n].name[name_idx++]=c;
}
if(c == ':')
{
// make sure that playTop[n].name is a c-string
playTop[n].name[name_idx] = 0;
fscanf(...);
}
...
}
One last thing:
It's not bad using an array for saving strings, the problem is that the
maximum length of the string is dimension or array - 1. In your case the
name must not be longer than 19 characters, otherwise you will have a buffer
overflow and you are going to write over memory that is not allocated for the
name, you will have undefined behaviour and anything could happen.
When you know that the max. length of your string won't pass certain value
(let's say 15), then it's fine to use char name[20]. If there's no guarantee
of a max. length, then you have to dynamically allocate memory for it using
malloc/realloc (and later you would have to free that memory).
Also, a better way to parse your line would be to use fgets to get the while
line and then parse it:
typedef struct STRUCT_PLAYER{char *name;
int sucess;
int numQuest;
int wrongs;} PLAYER;
int readTop(PLAYER playTop[]){
...
char line[1024];
fgets(line, sizeof line, fl);
int colon_index = strchr(line, ':');
// color_index is the index where : is in the line,
// the length of the name is colon_index - 1
// because you have to save \0 as well, you need to
// allocate one more space for the c-string
// name length + 1 ==> (colon_index - 1) + 1
// which equeals to colon_index
playTop[n].name = malloc(colon_index);
// copy the name from line into name. strncpy
// copies at most `colon_index - 1` characters, if
// \0 is not among them, it won't be appended at the end
// you have to do that
strncpy(playTop[n].name, line, colon_index - 1);
// making sure that name becomes a c-string
playTop[n].name[colon_index] = 0;
// sscanf is like fscan, only it takes the content from
// a string and not from a FILE object.
// line + colon_index + 1 ensures that sscanf reads only
// after the colon
sscanf(line + colon_index + 1, "...", ...);
}
Doing it this way, you ensure that the name can have any length. Note that
all these functions may fail: for example malloc might return NULL if
there is not enough memory, strchr might return NULL if a colon is not
found in the line (the line has a wrong format or is empty). The line itself could be
longer than 1024 bytes. For sake of simplicity I've omitted all those checks.
If you've understood my code, then you could make it better by checking for
the errors mentioned above. Read carefully the documentation of the functions
used here.
name is an array of characters and since you are copying character by character, need to use playTop[n].name[x]=c; since name is a character pointer doesn't make sense to compiler when you try to assign a character to it.
Array name is not a modifiable lvalue. You are assigning to it. Violating rules. That's why compiler complained. Even if it was modifiable you are having an incompatibility in type. Assigning a char to char[].
More logical would be to do this
playerTOP[n].nome[some_index]=c;
You have to store those characters in the nome member array of the struct.(which is a char array not char).
Also make int c and then do the check c!=EOF.
the whole, bug ridden:
while(c!=EOF){
while(c!=':'){
c=getc(fl);
if(c!=':') playTop[n].name=c;
}
if(c==':')fscanf(fl, " %d %d\n", &playTop[n].numQuest, &playTop[n].wrongs);
can be easily reduced (and should be reduced) to the clean:
while( 3 == fscanf( fl, " %19[^:]: %d %d",
playTop[n].name,
&playtop[n].numQuest,
&playTop[n].wrongs ) )
{
n++;
}

Initialize a string in C to empty string

I want to initialize string in C to empty string.
I tried:
string[0] = "";
but it wrote
"warning: assignment makes integer from pointer without a cast"
How should I do it then?
In addition to Will Dean's version, the following are common for whole buffer initialization:
char s[10] = {'\0'};
or
char s[10];
memset(s, '\0', sizeof(s));
or
char s[10];
strncpy(s, "", sizeof(s));
You want to set the first character of the string to zero, like this:
char myString[10];
myString[0] = '\0';
(Or myString[0] = 0;)
Or, actually, on initialisation, you can do:
char myString[10] = "";
But that's not a general way to set a string to zero length once it's been defined.
Assuming your array called 'string' already exists, try
string[0] = '\0';
\0 is the explicit NUL terminator, required to mark the end of string.
Assigning string literals to char array is allowed only during declaration:
char string[] = "";
This declares string as a char array of size 1 and initializes it with \0.
Try this too:
char str1[] = "";
char str2[5] = "";
printf("%d, %d\n", sizeof(str1), sizeof(str2)); //prints 1, 5
calloc allocates the requested memory and returns a pointer to it. It also sets allocated memory to zero.
In case you are planning to use your string as empty string all the time:
char *string = NULL;
string = (char*)calloc(1, sizeof(char));
In case you are planning to store some value in your string later:
char *string = NULL;
int numberOfChars = 50; // you can use as many as you need
string = (char*)calloc(numberOfChars + 1, sizeof(char));
To achieve this you can use:
strcpy(string, "");
string[0] = "";
"warning: assignment makes integer from pointer without a cast
Ok, let's dive into the expression ...
0 an int: represents the number of chars (assuming string is (or decayed into) a char*) to advance from the beginning of the object string
string[0]: the char object located at the beginning of the object string
"": string literal: an object of type char[1]
=: assignment operator: tries to assign a value of type char[1] to an object of type char. char[1] (decayed to char*) and char are not assignment compatible, but the compiler trusts you (the programmer) and goes ahead with the assignment anyway by casting the type char* (what char[1] decayed to) to an int --- and you get the warning as a bonus. You have a really nice compiler :-)
I think Amarghosh answered correctly. If you want to Initialize an empty string(without knowing the size) the best way is:
//this will create an empty string without no memory allocation.
char str[]="";// it is look like {0}
But if you want initialize a string with a fixed memory allocation you can do:
// this is better if you know your string size.
char str[5]=""; // it is look like {0, 0, 0, 0, 0}
It's a bit late but I think your issue may be that you've created a zero-length array, rather than an array of length 1.
A string is a series of characters followed by a string terminator ('\0'). An empty string ("") consists of no characters followed by a single string terminator character - i.e. one character in total.
So I would try the following:
string[1] = ""
Note that this behaviour is not the emulated by strlen, which does not count the terminator as part of the string length.

Resources