Different compilers are giving different outputs for the same logic in my algorithm.
I wrote the following code for a C code exercise.
The code checks for the longest string in a string vector.
But the same logic gives two different outputs.
Here's what is happening. I have no idea what I did wrong.
First version - without a printf() inside the if condition
Here the if (j > longest) just attributes new values for int longest and int index.
#include <stdio.h>
int main(void) {
char *vs[] = {"jfd", "kj", "usjkfhcs", "nbxh", "yt", "muoi", "x", "rexhd"};
int longest, index = 0;
/* i is the index for elements in *vs[].
* "jfd" is 0, "kj" is 1... */
for (int i = 0; i < sizeof(*vs); i++) {
/* j if the index for string lengths in vs[].
* for "jfd", 'j' is 0, 'f' is 1... */
for (int j = 0; vs[i][j] != '\0'; j++) {
/* if j is longer than the previous longest value */
if (j > longest) {
longest = j;
index = i;
}
}
}
printf("Longest string = %s\n", vs[index]);
return 0;
}
I ran it on https://replit.com/. It gave the unexpected output for longest string of "jfd". https://replit.com/#Pedro-Augusto33/Whatafuck-without-printf?v=1
Second version - with a printf() inside the if condition
Now I just inserted a printf() inside the if (jf > longest) condition, as seen in the code block bellow.
It changed the output of my algorithm. I have no idea how or why.
#include <stdio.h>
int main(void) {
char *vs[] = {"jfd", "kj", "usjkfhcs", "nbxh", "yt", "muoi", "x", "rexhd"};
int longest, index = 0;
/* i is the index for elements in *vs[].
* "jfd" is 0, "kj" is 1... */
for (int i = 0; i < sizeof(*vs); i++) {
/* j if the index for string lengths in vs[].
* for "jfd", 'j' is 0, 'f' is 1... */
for (int j = 0; vs[i][j] != '\0'; j++) {
/* if j is longer than the previous longest value */
if (j > longest) {
printf("Whatafuck\n");
longest = j;
index = i;
}
}
}
printf("Longest string = %s\n", vs[index]);
return 0;
}
I also ran it on https://replit.com/. It gave the expected output for longest string of "usjkfhcs". https://replit.com/#Pedro-Augusto33/Whatafuck-with-printf?v=1
Trying new compilers
After replit.com giving two different outputs, I tried another compiler to check if it also behaved strangely. https://www.onlinegdb.com/online_c_compiler gives random outputs. Sometimes it's "jfd", sometimes it's "usjkfhcs". https://onlinegdb.com/iXoCDDena
Then I went to https://www.programiz.com/c-programming/online-compiler/ . It always gives the expected output of "usjkfhcs".
So, my question is: why are different compilers behaving so strangely with my algorithm? Where is the flaw of my algorithm that makes the compilers interpret it different?
The code does not make sense.
For starters the variable longest was not initialized
int longest, index = 0;
So using it for example in this statement
if (j > longest) {
invokes undefined behavior.
In this for loop
for (int i = 0; i < sizeof(*vs); i++) {
the expression sizeof( *vs ) is equivalent to expression sizeof( char * ) and yields either 4 or 8 depending on the used system. It just occurred such a way that the array was initialized with 8 initializers. But in any case the expression sizeof( *vs ) does not provide the number of elements in an array and its value does not depend on the actual number of elements.
Using the if statement within the for loop in each iteration of the loop
for (int j = 0; vs[i][j] != '\0'; j++) {
/* if j is longer than the previous longest value */
if (j > longest) {
longest = j;
index = i;
}
}
Also does not make sense. It does not calculate the exact length of a string that is equal to j after the last iteration of the loop. So in general such a loop shall not be used for calculating length of a string.
Consider a string for example like "A". Using this for loop you will get that its length is equal to 0 while its length is equal to 1..
It seems you are trying to find the longest string a pointer to which stored in the array.
You could just use standard C string function strlen declared in header <string.h>. If to use your approach with for loops then the code can look the following way
#include <stdio.h>
int main(void)
{
const char *vs[] = { "jfd", "kj", "usjkfhcs", "nbxh", "yt", "muoi", "x", "rexhd" };
const size_t N = sizeof( vs ) / sizeof( *vs );
size_t longest = 0, index = 0;
for ( size_t i = 0; i < N; i++ )
{
size_t j = 0;
while ( vs[i][j] != '\0' ) ++j;
if ( longest < j )
{
longest = j;
index = i;
}
}
printf( "Longest string = %s\n", vs[index] );
printf( "Its length = %zu\n", longest );
return 0;
}
Related
Below code snippet from Leetcode. the given exercise is to find the longest substring without repeating characters. I am trying to understand the logic from someone has posted the solution
I have below question is
I have cnt and s are array. is this array inside array cnt[s[j]] and cnt[s[j]]++? how it works, please help to explain. I have tried to visualize the code execution using this
I have tried to understand below line . I tried to visualize the code execution using
#include <stdio.h>
int lengthOfLongestSubstring(char * s)
{
if (s[0] == '\0')
return 0;
if (s[1] == '\0')
return 1;
int i, j, len, max = 0;
int cnt[255] = {0}; // array of counter
//memset(cnt,0,sizeof(cnt));
for (i=0; s[i]!=0; i++)
{
len = 0;
for (j=i; s[j]!=0; j++)
{
if (cnt[s[j]] == 0) /* What does this mean since cnt and s both are array? is this called array inside array ? */
{
printf("iteration %d %c\n",j,s[j]);
cnt[s[j]]++;
len++;
}
else
{ /* if character are not equal */
break;
}
}
if (len > max)
max = len;
}
return max;
}
int main()
{
char string1[] = "abcabcbb";
printf("%d",lengthOfLongestSubstring(string1));
return 0;
}
The syntax a[b[i]] means the value in b[i] references the index from a to read.
So if you have int a[] = { 10, 100, 1000, 10000, 100000}; int b[] = { 3, 2, 1, 0}; then a[b[0]] resolves to a[3] which has the value 10000.
Note that this requires b to only have values that are valid indexes into a.
It's not an array inside an array, it's using one array to get the subscript into another array.
When you see a complex expression you don't understand, split it up into simpler expressions.
cnt[s[j]]++;
is roughly equivalent to
int charcode = s[j];
cnt[charcode]++;
s is a string, so s[j] contains a character code. So this increments the element of cnt corresponding to that character code, and the final result is frequency counts of each character.
Basically I am creating an array 'string' with some values in it, creating another array ('auxstring'), and then storing all the values of the initial array in reverse order. Finally I print them out.
How come when I execute the program as is, I get garbage as the output? However, if I put another number in the 'string' array (ie: {3,1,1,3,4}) it works fine (outputs: 43113).
It also works fine if I add this line:
"printf("%d\n", sizeof(auxstring));"
right before the for loop.
I'm sure it's something very basic, but I would like to understand what is going on behind the scene and why adding a number at the end of the initial string, or putting that printf, somehow outputs the accurate numbers.
Thanks.
#include <stdio.h>
#include <string.h>
int main(void) {
int i=0, j, l;
char string[] = {3,1,1,3};
char auxstring[sizeof(string)];
for (j=(sizeof(auxstring) - 1); j >= auxstring[0]; j--) {
auxstring[j] = string[i];
i++;
}
for (l=0; l < sizeof(auxstring); l++) {
printf("%d",auxstring[l]);
}
return 0;
}
The condition in the for loop
for (j=(sizeof(auxstring) - 1); j >= auxstring[0]; j--) {
^^^^^^^^^^^^^^^^^^
does not make sense because at least the array auxstring is not initialized.
Also the loop is complicated because it uses two variables as indices.
Ans the variables i, j, l should have the type size_t - the type of the returned value of the operator sizeof.
The program can look the following way
#include <stdio.h>
int main(void)
{
char string[] = { 1, 2, 3, 4 };
char auxstring[sizeof( string )];
const size_t N = sizeof( string );
for ( size_t i = 0; i < N; i++ )
{
auxstring[i] = string[N - i - 1];
}
for ( size_t i = 0; i < N; i++ )
{
printf( "%d", auxstring[i] );
}
return 0;
}
Its output is
4321
The loop condition should be j >= 0.
Right now you compare against the uninitialized value in auxstring[0], which is indeterminate (and will seem random).
I have written a C program to find out the number of similar characters between two strings. If a character is repeated again it shouldn't count it.
Like if you give an input of
everest
every
The output should be
3
Because the four letters "ever" are identical, but the repeated "e" does not increase the count.
For the input
apothecary
panther
the output should be 6, because of "apther", not counting the second "a".
My code seems like a bulk one for a short process. My code is
#include<stdio.h>
#include <stdlib.h>
int main()
{
char firstString[100], secondString[100], similarChar[100], uniqueChar[100] = {0};
fgets(firstString, 100, stdin);
fgets(secondString, 100, stdin);
int firstStringLength = strlen(firstString) - 1, secondStringLength = strlen(secondString) - 1, counter, counter1, count = 0, uniqueElem, uniqueCtr = 0;
for(counter = 0; counter < firstStringLength; counter++) {
for(counter1 = 0; counter1 < secondStringLength; counter1++) {
if(firstString[counter] == secondString[counter1]){
similarChar[count] = firstString[counter];
count++;
break;
}
}
}
for(counter = 0; counter < strlen(similarChar); counter++) {
uniqueElem = 0;
for(counter1 = 0; counter1 < counter; counter1++) {
if(similarChar[counter] == uniqueChar[counter1]) {
uniqueElem++;
}
}
if(uniqueElem == 0) {
uniqueChar[uniqueCtr++] = similarChar[counter];
}
}
if(strlen(uniqueChar) > 1) {
printf("%d\n", strlen(uniqueChar));
printf("%s", uniqueChar);
} else {
printf("%d",0);
}
}
Can someone please provide me some suggestions or code for shortening this function?
You should have 2 Arrays to keep a count of the number of occurrences of each aplhabet.
int arrayCount1[26],arrayCount2[26];
Loop through strings and store the occurrences.
Now for counting the similar number of characters use:
for( int i = 0 ; i < 26 ; i++ ){
similarCharacters = similarCharacters + min( arrayCount1[26], arrayCount2[26] )
}
There is a simple way to go. Take an array and map the ascii code as an index to that array. Say int arr[256]={0};
Now whatever character you see in string-1 mark 1 for that. arr[string[i]]=1; Marking what characters appeared in the first string.
Now again when looping through the characters of string-2 increase the value of arr[string2[i]]++ only if arr[i] is 1. Now we are tallying that yes this characters appeared here also.
Now check how many positions of the array contains 2. That is the answer.
int arr[256]={0};
for(counter = 0; counter < firstStringLength; counter++)
arr[firstString[counter]]=1;
for(counter = 0; counter < secondStringLength; counter++)
if(arr[secondString[counter]]==1)
arr[secondString[counter]]++;
int ans = 0;
for(int i = 0; i < 256; i++)
ans += (arr[i]==2);
Here is a simplified approach to achieve your goal. You should create an array to hold the characters that has been seen for the first time.
Then, you'll have to make two loops. The first is unconditional, while the second is conditional; That condition is dependent on a variable that you have to create, which checks weather the end of one of the strings has been reached.
Ofcourse, the checking for the end of the other string should be within the first unconditional loop. You can make use of the strchr() function to count the common characters without repetition:
#include <stdio.h>
#include <string.h>
int foo(const char *s1, const char *s2);
int main(void)
{
printf("count: %d\n", foo("everest", "every"));
printf("count: %d\n", foo("apothecary", "panther"));
printf("count: %d\n", foo("abacus", "abracadabra"));
return 0;
}
int foo(const char *s1, const char *s2)
{
int condition = 0;
int count = 0;
size_t n = 0;
char buf[256] = { 0 };
// part 1
while (s2[n])
{
if (strchr(s1, s2[n]) && !strchr(buf, s2[n]))
{
buf[count++] = s2[n];
}
if (!s1[n]) {
condition = 1;
}
n++;
}
// part 2
if (!condition ) {
while (s1[n]) {
if (strchr(s2, s1[n]) && !strchr(buf, s1[n]))
{
buf[count++] = s1[n];
}
n++;
}
}
return count;
}
NOTE: You should check for buffer overflow, and you should use a dynamic approach to reallocate memory accordingly, but this is a demo.
I wrote a function that finds the longest string in a 2d array, it works, partially. My problem is that it takes the first longest string that it finds without checking the other ones.
For example, the following list of strings:
eke
em
ekeke
eme
e
ememeememe
emem
ekekee
eooeeeeefe
eede
My function catches "ekeke" (the third string from the list) as the longest instead of "ememeememe ".
Here is my function:
void length(char str[][MAX])
{
int i = 0;
for(i = 1; i < LEN; i++)
{
if(strlen(str[i]) > strlen(str[i-1]))
{
if(strlen(str[i]) > strlen(str[i+1]))
{
printf("%s", str[i]);
break;
}
}
}
}
LEN is a constant, his value is 10.
MAX is a constant, his value is 50.
The strings are given by the user.
Thanks.
You are only comparing the previous and next strings. You need to check the lengths of all the strings.
void length(char str[][MAX])
{
size_t longest = strlen(str[0]);
szie_t j = 0;
for(size_t i = 1; i < LEN; i++)
{
size_t len = strlen(str[i]);
if(longest < len)
{
longest = len;
j = i;
}
}
printf("%s", str[j]);
}
I am assuming you have at least 1 string and handle corner cases (if user inputs less than LEN strings etc -- depends on how you fill the str with strings).
I wrote a function that finds the longest string in a 2d array, it works, partially. My problem is that it takes the first longest string that it finds without checking the other ones.
For example, the following list of strings:
eke
em
ekeke
eme
e
ememeememe
emem
ekekee
eooeeeeefe
eede
My function catches "ekeke" (the third string from the list) as the longest instead of "ememeememe ".
Here is my function:
void length(char str[][MAX])
{
int i = 0;
for(i = 1; i < LEN; i++)
{
if(strlen(str[i]) > strlen(str[i-1]))
{
if(strlen(str[i]) > strlen(str[i+1]))
{
printf("%s", str[i]);
break;
}
}
}
}
LEN is a constant, his value is 10.
MAX is a constant, his value is 50.
The strings are given by the user.
Thanks.
You are only comparing the previous and next strings. You need to check the lengths of all the strings.
void length(char str[][MAX])
{
size_t longest = strlen(str[0]);
szie_t j = 0;
for(size_t i = 1; i < LEN; i++)
{
size_t len = strlen(str[i]);
if(longest < len)
{
longest = len;
j = i;
}
}
printf("%s", str[j]);
}
I am assuming you have at least 1 string and handle corner cases (if user inputs less than LEN strings etc -- depends on how you fill the str with strings).