Different outputs - c

Why does the first code give a different output from the second code, even though they intend to do the same thing?
while(s[i++]==t[j++]);
while(s[i]==t[j])
{
i++;
j++;
}

The first code increments i and j even when s[i] != t[j], while the second doesn't.
For example, with:
char s[] = "hello";
char t[] = "world";
int i = 0, j = 0;
The first code will have both i and j equal to 1 after the loop, but the second code will have i and j equal to 0.

Related

Can't set second element of an empty string in C

I have this code, which doubles every letter in nabucco:
#include<stdio.h>
#include<string.h>
int main(){
char string1[20] = "nabucco";
char string2[40];
int j=-1;
for(int i=0; i<strlen(string1);i++){
j++;
string2[j] = string1[i];
j++;
string2[j] = string1[i];
}
printf("string1=\t%s\n",string1);
printf("string2=\t%s\n",string2);
}
string2 is set to and prints nnaabbuuccccoo.
However, when I try to set j=0; string2 prints (and is presumably set to) nothing.
If j=0 before going into the loop, then j is incremented to 1 in the for loop, which starts off setting the second element of the empty string2. Is there something behind the scenes preventing any element other than the first from being set? I do not understand what is causing this behavior.
The program as posted has undefined behavior since you don't put a null terminator in string2.
If you start with j=0, you never set the value of string2[0] since you increase j before using it, so that position remains indeterminable.
Possible fix:
#include<stdio.h>
#include<string.h>
int main(){
char string1[20] = "nabucco";
char string2[40];
size_t j=0;
for(size_t i=0, len = strlen(string1); i<len; i++) {
string2[j++] = string1[i]; // increase j "after" using the current value
string2[j++] = string1[i];
}
string2[j] = '\0'; // add null terminator
printf("string1=\t%s\n",string1);
printf("string2=\t%s\n",string2);
}
An alternative could be to initialize string2 when you create it:
#include<stdio.h>
#include<string.h>
int main(){
char string1[20] = "nabucco";
char string2[40] = {0}; // zero initialized
for(size_t i=0, j=0, len = strlen(string1); i<len; i++) {
string2[j++] = string1[i];
string2[j++] = string1[i];
}
printf("string1=\t%s\n",string1);
printf("string2=\t%s\n",string2);
}
You increment the counter before using it the first time, so if you set j=0 you do j++ before using it first, which means you start with string2[1].
You can change it like so:
int j=0;
for(int i=0; i<strlen(string1);i++){
string2[j] = string1[i];
j++;
string2[j] = string1[i];
j++;
}
When you do this
printf("string2=\t%s\n",string2);
and string2 was set from the second character, this is a sort of undefined behaviour (see also this answer). string2[0] was not initialised, and could contain anything (from sensitive data to something that can't be parsed successfully by other functions - okay, here it is a single character; in other circumstances it could be more than that, if you started with j=20 for example). Which is why undefined behaviour is to be avoided at all costs.
In this case, the quirks of platform, compiler and process made it so the first character is a zero. Since C strings are zero-terminated, and string2 begins with a zero, printf prints nothing. If you printed something like this, where "." is a 0 character (ASCII 0),
"nnaa.bbuuccoo."
you would get only "nnaa". By the same token, printf'ing ".nnaabbuuccoo" gets you nothing.
If you were to print string2 starting at the second character, you'd get different results:
printf("string2=\t%s\n",string2 + 1);
After the for loop the character array string2 does not contain a string because you forgot to append it with the terminating zero character '\0'. So this call of printf
printf("string2=\t%s\n",string2);
invokes undefined behavior.
A simplest approach to resolve the problem is to initialize the array in its declaration. For example
char string2[40] = "";
As for this statement
However, when I try to set j=0; string2 prints (and is presumably set
to) nothing.
then within the for loop the variable j is at once incremented.
int j = 0;
for(int i=0; i<strlen(string1);i++){
j++;
string2[j] = string1[i];
//...
So the first character of the array string2 is not set.
In this case it is better to write the for loop the following way
size_t j = 0;
for ( size_t i = 0, n = strlen( string1 ); i < n; i++ ){
string2[j++] = string1[i];
string2[j++] = string1[i];
}
string2[j] = '\0';
It is because strings in C are null terminated. So when you set j=0 outside of loop, you skip setting first character which remains null.

Something's wrong with my reverse string function

So it seems it works when I reversed "hello", but it prints out something weird like
"ol▒eh"
in the middle. It's gone when I fixed
i< length/2;
to
i<= length/2;
Isn't the first one supposed to be the right one?
what's the ▒ character mean in C? is it something like Null?
void reverse_copy(char dest[], const char src[]){
size_t i;
char temp;
size_t length = (size_t)strlen(src);
for(i = 0; i <= length/2; i++){ /*?? why i<length/2 is not working*/
dest[i] = src[length-i-1];
temp = src[i];
dest[length-i-1] = temp;
}
}
The main problem with i< length/2; is that it may leave out the "middle" element in case of odd string lenght of src. Hence, the middle element in dest may remain uninitialized, showing up as some "arbitrary" ASCII value then.
But in general, your code is appropriate for reverse_in_place, where you have to take care of not overwriting something that you need later in the loop for copying.
If you do a reverse_copy, however, it is sufficient - or better - to simply have one reverse loop:
void reverse_copy(char dest[], const char src[]){
size_t i;
size_t length = strlen(src);
for(i = 0; i < length; i++){
dest[i] = src[length-i-1];
}
dest[i] = '\0';
}
With :
for(i = 0; i < length/2; i++){
you never set the middle character (for odd lengths) in dest.
With your example "hello", length/2 is 2, so you set (for i = 0) :
dest[0] = src[5-0-1]; // dest[0] = src[4]
dest[5-0-1] = src[0]; // dest[4] = src[0]
and then (for i = 1) :
dest[1] = src[5-1-1]; // dest[1] = src[3]
dest[5-1-1] = src[1]; // dest[3] = src[1]
and that's it. You never set dest[2].
Because i<length/2 is already based on integer division, i.e: it will floor the result. This will skip the middle element in case of odd length strings.
To understand what is happening in the code, a debugger would help.
You need to step through the code line by line and watch what is the value of i and length - i - 1.
The reason a strange character appears in the middle is that if length is odd then the middle item is skipped when the condition is <.
For example, when length == 5 then 5/2 == 2 (because of integer division 2.5 comes out to be 2 ).
So analysing the loop:
i=0
is i < 2. Yes, so continue code block.
dest[0] = src[4]
temp = src[0]
dest[4] = temp
i++ i is 1
is i < 2. Yes, so continue code block.
dest[1] = src[3]
temp = src[1]
dest[3] = temp
i++ i is 2
is i < 2. No, so exit the loop
So looking at the steps (especialialy steps 3,5,8,10) only dest[0], dest[1], dest[3], dest[4] are written from the source when checking <.
Destination 2 is not changed.
This problem does not arise for even numbers.
As dest[2] was not updated then the character which was already there, is been displayed. Which could be any random character. If it was initialized to 0 (a null) then that is the character that represents 0.
But looking at that character it looks more like a value 177 (extended ASCII codes :http://www.asciitable.com/)
Also I find this definition of reverse_copy very error prone, as it it doesn't know how big the destination buffer is. It can overwrite something if it is too small.
In this case I would use a sentinel to mark the end of the string, and use a while loop:
void reverse_copy(char dest[], const char src[])
{
const char* src_end = src + strlen(src) - 1;
--src;
while (src_end > src)
{
*dest = *src_end;
++dest;
--src_end;
}
*dest = '\0';
}

How to reset a string in C

I have this string
char currentString[212] = { 0 };
and after I'm using it once, I want to reset it.
I tried many ways, such as:
for (int k = 0; k < strlen(currentString); k++)
{
currentString[k] = '\0';
}
but it won't go over the loop more than once, and it give '\0' only to the first char, the rest remain the same.
and I also tried:
currentString[0] = '\0';
yet I get the same result.
any suggestions for what can I do?
thanks!
strlen will find the length by searching for the first occurrence of \0. So if you want to reset the whole array, you should change strlen(currentString) to sizeof currentString. However, do note that this will not work with pointers.
If you pass the array to a function, you cannot determine the size of the array afterwards, so this will not work:
void foo(char * arr) {
for (int k = 0; k < sizeof arr; k++)
arr[k] = '\0';
}
Instead you need to do like this:
void foo(char * arr, size_t size) {
for (int k = 0; k < size; k++)
arr[k] = '\0';
}
But of course there's no reason to write custom functions for this when memset is available.
Imagine char currentString[] = "abc"; and then running you loop:
k = 0
initialy strlen(currentString) = 3, there are 3 characters before '\0' byte. the loop condition k < strlen(currentString) is true
k = 0 -> currentString[0] = '\0'
k++ -> k = 1
then strlen(currentString) = 0 (as the first byte of currentString is equal to '\0', there are no characters before '\0')
the loop condition is false k < strlen(currentString) -> 1 < 0
So the loop will always run only one time.
If you want to write only zero bytes to a memory region, use memset
memset(currentString, 0, sizeof(currentString));
will set the memory region as pointed to by currentString pointer with sizeof(currentString) bytes to zeros.
Setting the first byte to zero:
currentString[0] = '\0';
maybe considered enough to "clear a string".
Setting the first byte to '\0' wont clear out the currentString.You may think that because ANSI C thinks that is a string terminator and if you print your string it will show empty.But if you check the second byte you will see the second char from your string. As other's said the best option to wipe out the string is:
memset(currentString, 0, sizeof(currentString));
And is way safer and faster.Also in ANSI C 0 and '\0' are the same.
to zero the whole array
char arr[SOMESIZE];
/* ... */
memset(arr, 0, sizeof(arr));
pointer - you need to know the size of the allocated memory as sizeof will return the size of the pointer itself only, not the referenced object;
char *p = malloc(SIZE);
/* ..... */
memset(p, 0 , SIZE);
It is never a good decision to calculate anything again and again. Instead you should calculate the strlen() only once.
That being said, in your case, doing so will solve the problem, as the reason it didn't work was that strlen() returned 0 right after the first round, since the length of the string became 0.
int n = strlen(currentString);
for (int k = 0; k < n; k++)
{
currentString[k] = '\0';
}

Swapping elements of char array in C

I have this code:
char *sort(char *string){ //shell-sort
int lnght = length(string) - 1; // length is my own function
int gap = lnght / 2;
while (gap > 0)
{
for (int i = 0; i < lnght; i++)
{
int j = i + gap;
int tmp =(int)string[j];
while (j >= gap && tmp > (int)string[j - gap])
{
string[j] = string[j - gap]; // code fails here
j -= gap;
}
string[j] = (char)tmp; // and here as well
}
if (gap == 2){
gap = 1;
}
else{
gap /= 2.2;
}
}
return string;
}
The code should sort (shell-sort) the characters in the string, given the ordinal value (ASCII value). Even though the code is pretty simple, it still fails at lines I've commented - segmentation fault. I've spent plenty of time with this code and still can't find the problem.
As you say in comment , you call our function like this -
char *str = "test string";
sort(str);
String literal is in read-only memory and creates a pointer str to that, thus it cannot be modified , and your function modifies it . Therefore ,it can result in segmentation fault .
Declare like this -
char str[] = "test string";
In situations like this look at your statements not so much as executable code, but as mathematical boundary conditions. I've replaced the monstrous name lnght with length for readability purposes.
Here are the relevant conditions that affect the value of j when entering the while loop, relative to the length.
i < length;
gap = length / 2;
j = i + gap;
Now we plug in a value. Consider the case where length == 10. Then presumably the maximum index in your array is 9 which is also the highest value that i can take on.
Then we also have that gap == 5 and so after entering the while loop j == i + gap == 9 + 5. Clearly 9 + 5 > 10. The rest is left as an exercise to the programmer.
How do you test your function? With a static string (i.e. char *buffer = "test string";) ?
Because on first loop at least j and j-gap should be inside the string boundaries. So if you get a segfault I guess it is because of a bad string (statics can't be modified).
Replacing length() by strlen() and calling it with a well-created test string lead me to a valid result:
"adgfbce" → "gfedcba"

printf() prints whole char matrix

As marked in the code, the first printf() rightfully prints only the i-th line of the matrix. But outiside the loop, both printf() and strcat() act on the whole matrix from i-th line on as a single-lined string. This means that
printf("%s\n",m_cfr[0])
will print whole matrix, but m_cfr[i] will print whole matrix from the i-th line on. char* string is a single lined string with no spaces.
trasp(char* string)
{
int row = strlen(string) / 5;
char m[row][5];
char m_cfr[row][5];
char cfr[row*5];
memset(cfr, 0, row * 5);
int key[5] = {3, 1, 2, 0, 4};
int k = 0;
for (i = 0 ; i < row ; i++)
{
strncpy(m[i], string + k, 5);
m[i][5] = '\0';
k += 5;
}
for (i = 0 ; i < row ; i++)
{
for (j = 0 ; j < 5 ; j++)
{
m_cfr[i][key[j]] = m[i][j];
}
m_cfr[i][5] = '\0';
printf("%s\n", m_cfr[i]); //--->prints only line i
}
printf("%s\n", m_cfr[0]); //prints whole matrix
strcat(cfr, m_cfr[0]); //concatenates whole matrix
printf("%s\n", cfr);
}
In your code, your array definition is
char m_cfr[row][5];
while you're accessing
m_cfr[i][5] = '\0';
/* ^
|
there is no 6th element
*/
You're facing off-by-one error. Out-of-bound memory access causes undefined behaviour.
Maybe you want to change the null-terminating statement to
m_cfr[i][4] = '\0'; //last one is null
%s expects a char* and prints everything until it encounters a \0. So,
printf("%s\n", m_cfr[i]);
printf("%s\n",m_cfr[0]);
strcat(cfr,m_cfr[0]);
All exhibit Undefined Behavior as m_cfr[i],m_cfr[0] and m_cfr[0] are chars and not char*s and %s as well as both the arguments of strcat expects a char*. Also, as SouravGhosh points out, using
m_cfr[i][5] = '\0';
And
m[i][5] = '\0';
Are wrong.
To fix the former issue, use
printf("%s\n", &m_cfr[i]);
printf("%s\n",m_cfr);
strcat(cfr,&m_cfr[0]);
To print the whole string and concatenate the two strings in the arguments of strcat or if you wanted to print just the chars, use
printf("%c\n", m_cfr[i]);
printf("%c\n",m_cfr[0]);
As for the latter issue, use
char m[row][5]={{0}};
char m_cfr[row][5]={{0}};

Resources