Two null termination signs at the end of a string in C - c

I'm learning C via "The C Programming Language" book. During one of the exercises, where it's needed to concatenate two strings, I found that there are two null terminating signs (\0) at the end of a resulting string. Is this normal?
Code for the function:
void
copy_str_to_end(char *target, char *destination)
{
while (*destination != '\0')
++destination;
while ((*destination++ = *target++) != '\0')
;
}
Output:
This is a destination. This is a target. Here's everything seems to be OK, but if I run this function to test:
void
prcesc(char *arr)
{
int i;
for (i = 0; i <= strlen(arr) + 1; i++)
if (arr[i] != '\0')
printf("%c", arr[i]);
else
printf("E");
printf("\n");
}
The problem becomes visible: This is a destination. This is a target.EE (E means \0)
So, should I worry about this or not? And if yes, what's the reason for this thing to happen?

The problem is basically caused by the use of the <= operator instead of the < operator inside of the for loop condition:
i <= strlen(arr) + 1
strlen(arr) + 1 gives the amount of elements in the array, arr is pointing to in the caller (which actually contains the string).
When you use i <= strlen(arr) + 1 the loop iterates one time more than expected and you attempt to access an element beyond the bound of the array at the last iteration with
if (arr[i] != '\0')
since index counting starts at 0, not 1.
To access memory beyond the bounds of the array invokes undefined behavior.

The extra E in output is because you are running the while loop in prcesc function for i = strlen(arr) + 1 also. strlen returns the length of string say 'n'. So arr[n-1] is the last element of string and all elements from arr[n] are '\0'.
Hence as you are iterating for both arr[n], arr[n+1], you are getting two null characters.
The following function is what you need :
void
prcesc(char *arr)
{
int i;
for (i = 0; i <= strlen(arr); i++)
if (arr[i] != '\0')
printf("%c", arr[i]);
else
printf("E");
printf("\n");
}

Related

anything wrong with this trim() method in C

this method is for trimming a string in C by deleting spaces from the beginning and end.
BTW iam not that good with C and actually facing some issues with dealding with strings
char* trim(char s[])
{
int i, j;
int size = strlen(s);
//index i will point to first char, while j will point to the last char
for(i = 0; s[i] == ' '; i++);
for(j = size - 1; s[j] == ' '; j--);
if(i > 0)
s[i - 1] = '\0';
if(j < size - 1)
s[j + 1] = '\0';
s = &s[i];
return s;
}
This loop
for(j = size - 1; s[j] == ' '; j--);
will access an out-of-bounds index when:
the input string consists entirely of spaces (e.g., " "), in which case there is nothing stopping j from reaching -1 and beyond, or
the input string is the empty string (""), where j starts at -1.
You need to guard against this in some way
for (j = size - 1; j >= 0 && s[j] == ' '; j--)
The other thing to consider is that you are both: modifying the contents of the original string buffer, and potentially returning an address that does not match the beginning of the buffer.
This is somewhat awkward, as the user must take care to keep the original value of s, as its memory contains the trimmed string (and might be the base pointer for allocated memory), but can only safely access the trimmed string from the returned pointer.
Some things to consider:
moving the trimmed string to the start of the original buffer.
returning a new, dynamically allocated string.
Some people have warned that you cannot pass a string literal to this function, which is true, but passing a string literal to a non-const argument is a terrible idea, in general.

Runtime error: reading uninitialized value, how can I fix it?

This function is basically just supposed to compare 2 strings and return their ASCII difference if they are different. It works perfectly fine when I compile it with the GCC compiler, but when I run it through the online compiler that is used to upload our classes homework, I get this error message:
Error near line 98: Reading an uninitialized value from address 10290
Line 98 is marked in the below code. I am not quite sure what the problem is and how I'm supposed to fix it. Does anyone have an idea?
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i]; // line 98
if (difference != 0) {
return difference;
}
}
return difference;
}
Your code can skip over EOLN, if string equals, and try to compare memory after end of lines. To fix this, you need instantly return, if both string equals, and you see EOLN char '\0' in both strings at position i. Try my fix:
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i];
if (difference != 0 || pStr1[i] == '\0') {
return difference;
}
}
return difference;
}
The problem in your code is that you fail to check the real length of the strings before indexing them. You are iterating with i from 0 to 99, but you do not check for the NUL terminator (\0) that marks the end of a string and therefore your for loop goes beyond the end of the string resulting in undefined behavior accessing memory that is not supposed to (which is what the error is telling you).
The correct way to iterate over a string, is not to loop a fixed amount of cycles: you should start from index 0 and check each character of the string in the loop condition. When you find \0, you stop. See also How to iterate over a string in C?.
Here's a correct version of your code:
int stringCompare(char *pStr1, char *pStr2) {
size_t i;
for (i = 0; pStr1[i] != '\0' && pStr2[i] != '\0'; i++) {
if (pStr1[i] != pStr2[i])
break;
}
return pStr1[i] - pStr2[i];
}
You could even write this more concisely with a simple while loop:
int stringCompare(char *pStr1, char *pStr2) {
while (*pStr1 && *pStr1 == *pStr2) {
pStr1++;
pStr2++;
}
return *pStr1 - *pStr2;
}
Of course, both the above functions expect two valid pointers to be passed as arguments. If you also want to allow invalid pointers you should check them before starting the loop (though it does not seem like you want to do that from your code).

How do I replace all occurrences in an array with another array in C

I want to replace all occurrences in an array (string) with another array.
I have a code that:
stores the string in an array in which the replacing is to take place output[],
another array that stores the string to be searched for as replace[] and a third array called toBeReplacedBy and the replacing of the first occurrence works just fine but it skips the other occurrences in the output
for example:
replace[]:
abc
toBeReplacedBy[]:
xyz
output[]:
abcdefabc
becomes
xyzdefabc
but it should become:
xyzdefxyz
I suspect the problem lies with the replacer code :
//the replacer
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
//debug purpose
puts("output[]:\n");
puts(output);
return 0;
}
What have I done wrong here and how could I get it to replace all occurrences in the array.
please be aware that I only wish to use stdio.h to do this
thabks in advance
Never iterate further than the array length. This leads to undefined and possibly dangerous behaviour. If you only expect strings, use something like:
int i = 0;
while(output[i] != '\0')
{
// your logic here
i++;
}
Additionally you want to check for concurrent appearances of the same characters. But in your code you only check the first three characters. Everything after that is undefinded behaviour, because you cannot know what replace[3] returns.
Something similar to this could work:
int i = 0;
int j = 0;
int k;
while(output[i] != '\0')
{
if (output[i] == replace[j])
j++;
else
j = 0;
// replace 3 with the array length of the replace[] array
if (j == 3)
{
for(k = i; j >= 0; k-- )
{
output[k] = toBeReplacedBy[j]
j--
}
j = 0;
}
i++;
}
But please check the array boundaries.
edit: Additionally as Nellie states using a debugger would help you to understand what went wrong. Go through your program step by step and look how and when values change.
First advice is to try to debug your program if it does not work.
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
There are two problems in this loop.
The first is that are iterating until i is 80. Let's look what happens when i becomes 3. output[3] in case of abcdefabc is d, but what is replace[3]? Your replacement array had only 3 letters, so you have to go back in the replacement array once you finish with one occurrence of it in the original string.
The second is that you check letter by letter.
Say you original array, which you named output somehow was abkdefabc, first three letters do not match your replacement string, but you will check the first two letters they will match with the replacement's first two letters and you will incorrectly change them.
So you need to first check that the whole replacement string is there and only then replace.
You should use strlen() to know length of your array or iterate until you reach the end of a your array ('\0').
'\0' and strlen are only available for array of char.
Your loop should looks like this :
int i = 0;
int len = strlen(my_string);
while (i < len)
{
//logic here
i = i + 1;
}
OR
int i = 0;
while (my_string[i] != '\0')
{
// logic here
i = i + 1;
}

2D string array is storing '\0' when it encounters a word with more than one space or digit

I am pretty new to C programming. My program is supposed to take a string and move it into a 2D array. With the words either being separated by a white-space or a digit. This works perfectly fine if there is one space or digit separating it. However, as soon as there is more than one it starts adding '\0' to my array.
//Move the string into a 2D array
for(i = 0; i < total + 1; i++)
{
if(isalpha( *(tempString + i) ))
{
sortingArray[n][j++] = tempString[i];
input++;
}
else
{
sortingArray[n][j++] = '\0';
n++;
j = 0;
}
if(tempString[i] == '\0')
break;
}
This is a sample of what happens (n = number of rows placed)
./a.out "one more way"
5 inputs
before
one
more
way
After
one
more
way
You need to skip consecutive delimiters:
for(i = 0; i < total; i++)
{
if(isalpha(tempString[i]))
{
sortingArray[n][j] = tempString[i];
++j;
++input;
}
else
{
// skip consecutive delimiters
while (i < total && !isalpha(tempString[i]))
++i;
sortingArray[n][j] = '\0';
++j
++n;
j = 0;
}
}
Disclaimer: not verified by a compiler. Use caution!
I also took the liberty of some improvements to your original code.
there is no sense to check for \0 if you have the length of the string.
changed *(tempString + i) to the clear tempString[i]
moved the increments out of the larger expressions into their own full expression. It is clearer this way.
It's a simple logic failure for which a debugger is ideal for identifying.
Imagine you have the string "hello world".
It stores "hello" into sortingArray[0] easily enough. When it gets to the first space it increments n and starts looking for the next word. But the next character it finds is another space so it increments n again.
A slight change is required to your logic
if(isalpha( *(tempString + i) ))
{
sortingArray[n][j++] = tempString[i];
input++;
}
else if(j>0)
{
sortingArray[n][j++] = '\0';
n++;
j = 0;
}
Now the code will only increment n if the previous character was a letter (by virtue of j being more than 0). Otherwise if it doesn't care and will keep going.
You should also check to see if j is non-zero after the loop as that means there is a new entry in sortingArray that needs a NUL added.
One thing also to note is that the way you're doing the for loop is a little odd. You have this
for(i = 0; i < total + 1; i++)
but also this inside the loop
if(tempString[i] == '\0')
break;
Typically, the way to terminate the for loop would be to write it like this
for(i = 0; tempString[i]!='\0'; i++)
as that way you firstly don't care about the length of the string, but the loop will finish when it hits the NUL character.

Converting date format format from dd/mm/yyyy to yyyy/mm/dd using C

The inner while loop executes infinitely though the value of i = n which is finite.
It compiles but shows segmentation fault.
My Code
char s[]="22/02/1997",r[20],temp[20];
int i,j,k,z,n;
for(n=strlen(s)-1; n>=0; n=i)
{
i=n;
k=0;
while(s[i]!='/' || s[i]!='-')
{
temp[k++]=s[i];
i--;
}
i--;
for(z=strlen(temp)-1,j=0; z>=0; z--,j++)
{
r[j]=temp[z];
}
temp[0]='\0'; //empty the array
}
printf("%s",r);
There are multiple issues in your code.
The j = 0 will be outside of all loop. Which means it have to be placed in starting of outer for loop.
You did not handled the assign null value correctly. In any place you did not assigned the null at end of the array.
Your expected answer is yyyy/mm/dd. But you did not assigned the / or - to the output.
In while loop, you have add one more condition also, that is checking the value of the i is greater than or equal to 0. If this condition is not there, then it tries to access the -1th position in array, it is not allocated. So, only you get the segmentation fault error.
Finally I have corrected these all mistakes. Try the below code it will works fine as you expected.
#include<stdio.h>
#include<string.h>
int main()
{
char s[]="12/02/1997",r[50],temp[50];
int i,j,k,z,n;
j = 0;
for(n=strlen(s)-1; n>=0; n=i)
{
i=n;
k=0;
while(s[i]!='/' && s[i]!='-' && i >= 0)
{
temp[k++]=s[i];
i--;
}
i--;
temp[k] = '\0';
for(z=strlen(temp)-1; z>=0; z--,j++)
{
r[j]=temp[z];
}
if(i >= 1) // If the i is greater than 1, then only it have a slash or hypen
{
r[j++] = s[i + 1]; //Assigning the / or - to the output.
}
temp[0]='\0'; //empty the array
}
r[j] = '\0';
printf("%s\n",r);
}
The inner while loop executes infinitely ....
That is because you use OR (aka ||) instead of AND (aka &&). So your condition
(s[i] != '/' || s[i] != '-')
will always be true. It should at least be (see later code):
(s[i] != '/' && s[i] != '-')
.... but shows segmentation fault.
That is a consequence of the infinite loop. Since the loop keeps incrementing/decrementing k and i, you'll end up using indexes outside the array boundary which causes the crash.
Further you should check that i doesn't become -1 and, for completeness, check that k doesn't get too large.
You should also make sure to terminate the temp string as you are using strlen(temp)
Something like:
while(i>=0 && k<19 &&s[i]!='/' && s[i]!='-')
{
temp[k++]=s[i];
i--;
}
temp[k] = '\0'; // Terminate temp
Notice: There are some problems with your second loop as well but once you have solved the above, you can start looking into that part.

Resources