C program - largest word in a 2d array string [duplicate] - c

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

Related

Inconsistent output given by same code on different C compilers

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;
}

Print array of strings vertically

I know how to print a single string vertically.
char test[100] = "test";
int i;
for(i=0;i<strlen(test);i++){
printf("%c\n",test[i]);
}
Which will give me:
t
e
s
t
But how can I print an array of strings vertically? For example:
char listOfTest[2][10] = {"testing1","quizzing"};
So it can return:
tq
eu
si
tz
iz
gi
1g
Simply loop through the first string and print each character at index i in the first string and the second string till you reach the null terminator of first string
NOTE: this only work when string 1 and string2 are equal in length and will need modification for other test cases
#include <stdio.h>
int main(void)
{
char listOfTest[2][10] = {"testing1","quizzing"};
int i = 0;
//loop through string 1 till NULL is reach
while (listOfTest[0][i])
{
//prints char at index i in string 1 and 2
printf("%c%c\n", listOfTest[0][i], listOfTest[1][i]);
//increment the index value
i++;
}
return (0);
}
Simply print a character from both strings.
(Better to test for the null character rather than repeatedly call strlen().)
for(i = 0; listOfTest[0][i] && listOfTest[1][i]; i++) {
printf("%c%c\n", listOfTest[0][i], listOfTest[1][i]);
}
To extend to n strings ...
size_t num_of_strings = sizeof listOfTest/sizeof listOfTest[0];
bool done = false;
for (size_t i = 0; listOfTest[0][i] && !done; i++) {
for (size_t n = 0; n < num_of_strings; n++) {
if (listOfTest[n][i] == '\0') {
done = true;
break;
}
printf("%c", listOfTest[n][i]);
}
printf("\n");
}

Find if 2 strings are composed of same letters

I have a problem, this function should return 1 if secret is composed of same letters than letters_guessed.
It works fine, as long as letters_guessed has atleast 1 same letter which are in the secret. If there is same letter 2 times or more, it does not work. I know why, but I can not solve it because I can not remove same letters.
I can not remove same letters from letters_guessed array, because it is constant, and I can not change it to nonconstant.
Again ...
If:
secret = "cat"
letters_guessed = "txaoc"
return 1
**Right**
If:
secret = "dog"
letters_guessed = "gefxd"
return 0
**Right**
If:
secret = "car"
letters_guessed = "ccr"
return 1
**Wrong, How can I solve this?**
Sorry for my bad English and long explanation.
Here is my program:
int is_word_guessed(const char secret[], const char letters_guessed[])
{
int same = 0;
for(int i = 0; i < strlen(letters_guessed); i++)
{
for(int j = 0; j < strlen(secret); j++)
{
if(letters_guessed[i] == secret[j])
same++;
}
}
if (same == strlen(secret))
return 1;
else
return 0;
}
You can:
make a copy of your strings in order to flag already counted letters (since you tell you don't want to modify the strings, I suggest making a copy first in order to discard already counted letters);
get sorted versions of your strings and then compare them with a single loop; this solution would also provide a better complexity (you could get O(n log n) instead of your current O(n^2)).
One way to do this without modifying the strings is to count the occurrences of letters in the strings. When the guess has more occurrences of a letter than the secret, it's a miss. The case where a letter occurs in the guess that isn't in the secret is just a special case, because then the count of occurrences in the secret is zero.
In practice, you don't keep two separate counts: Add the letters of the guess to the count first, then remove the letters of the secret. As soon as one count drops below zero, it's a miss.
You can make use of the fact that there are only 256 different chars and keep the counts in an array. The index to the array is the letter's ASCII code. Be careful not to access the array at negative indices. C's char isn't guaranteed to be unsigned, so you could cast it or use an unsigned temporary variable or chose not to consider negative values.
Here's an implementation:
int contains(const char *guess, const char *secret)
{
int count[256] = {0}; // start with all-zero array
while (*guess) {
unsigned char c = *guess++;
count[c]++;
}
while (*secret) {
unsigned char c = *secret++;
if (count[c] == 0) return 0;
count[c]--;
}
return 1;
}
You can keep iteration in memory by maintaining an array of all 26 alphabets.
Assumptions:- All letters should be in lower case. Secret should not have repeated letters.
Logic:- Make array entry to 1 if we have considered that letter. 97 is ascii value of 'a'
// declare header file
#include "string.h"
int is_word_guessed(const char secret[], const char letters_guessed[])
{
int same = 0;
int alphabets[26];
// make all enteries 0
for (int k = 0; k <= 25; k++)
{
alphabets[k] = 0;
}
for (int i = 0; i < strlen(letters_guessed); i++)
{
for (int j = 0; j < strlen(secret); j++)
{
if (letters_guessed[i] == secret[j] && (alphabets[(char)letters_guessed[i] - 97] == 0))
{
same++;
alphabets[(char)letters_guessed[i] - 97] = 1;
}
}
}
if (same == strlen(secret))
return 1;
else
return 0;
}
It's easy.
In Haskell it would be:
all (`elem` letters_guessed) secret
in other words: All chars in secret must be in letters_guessed.
In C its (not tested):
// Iterate though string 'secret' until there is a char not
// part of 'letters_guessed'. If there is none, return 1
unsigned check(char *secret, char *letters_guessed) {
unsigned length_secret = length(secret);
unsigned length_guessed = length(letters_guessed);
for (int i = 0; i < length_secret; i++) {
if (!elem(secret[i], letters_guessed) {
return 0;
}
}
return 1;
}
// Check if char 'current' is part of 'string'
unsigned elem(char current, char *string) {
unsigned length = length(string);
unsigned found = 0;
for (int i = 0; i < length; i++) {
if (current == string[i]) {
return 1;
}
}
return 0;
}

First Not Repeating Character Code

Here is the question:
Write a solution that only iterates over the string once and uses O(1) additional memory, since this is what you would be asked to do during a real interview.
Given a string s, find and return the first instance of a non-repeating character in it. If there is no such character, return '_'.
And here is my code:
char firstNotRepeatingCharacter(char * s) {
int count;
for (int i=0;i<strlen(s);i++){
count=0;
char temp=s[i];
s[i]="_";
char *find= strchr(s,temp);
s[i]=temp;
if (find!=NULL) count++;
else return s[i];
}
if (count!=0) return '_';
}
I dont know what's wrong but when given an input:
s: "abcdefghijklmnopqrstuvwxyziflskecznslkjfabe"
the output is for my code is "g" instead of "d".
I thought the code should have escaped the loop and return "d" soon as "d" was found.
Thx in advance!!!
In your program, problem is in this statement-
s[i]="_";
You are assigning a string to a character type variable s[i]. Change it to -
s[i]='_';
At the bottom of your firstNotRepeatingCharacter() function, the return statement is under the if condition and compiler must be giving a warning for this as the function is supposed to return a char. Moreover, count variable is not needed. You could do something like:
char firstNotRepeatingCharacter(char * s) {
for (int i=0;i<strlen(s);i++){
char temp=s[i];
s[i]='_';
char *find= strchr(s,temp);
s[i]=temp;
if (find==NULL)
return s[i];
}
return '_';
}
But this code is using strchr inside the loop which iterates over the string so, this is not the exact solution of your problem as you have a condition that - the program should iterates over the string once only. You need to reconsider the solution for the problem.
May you use recursion to achieve your goal, something like - iterate the string using recursion and, somehow, identify the repetitive characters and while the stack winding up identify the first instance of a non-repeating character in the string. It's implementation -
#include <stdio.h>
int ascii_arr[256] = {0};
char firstNotRepeatingCharacter(char * s) {
char result = '-';
if (*s == '\0')
return result;
ascii_arr[*s] += 1;
result = firstNotRepeatingCharacter(s+1);
if (ascii_arr[*s] == 1)
result = *s;
return result;
}
int main()
{
char a[] = "abcdefghijklmnopqrstuvwxyziflskecznslkjfabe";
printf ("First non repeating character: %c\n", firstNotRepeatingCharacter(a));
return 0;
}
In the above code, firstNotRepeatingCharacter() function iterates over the string only once using recursion and during winding up of the stack it identifies the first non-repetitive character. I am using a global int array ascii_arr of length 256 to keep the track of non-repetitive character.
Java Solution:
Time Complexity: O(n)
Space Complexity: with constant space as it will only use more 26 elements array to maintain count of chars in the input
Using Java inbuilt utilities : but for inbuilt utilities time complexity is more than O(n)
char solution(String s) {
char[] c = s.toCharArray();
for (int i = 0; i < s.length(); i++) {
if (s.indexOf(c[i]) == s.lastIndexOf(c[i]))
return c[i];
}
return '_';
}
Using simple arrays. O(n)
char solution(String s) {
// maintain count of the chars in a constant space
int[] base = new int[26];
// convert string to char array
char[] input = s.toCharArray();
// linear loop to get count of all
for(int i=0; i< input.length; i++){
int index = input[i] - 'a';
base[index]++;
}
// just find first element in the input that is not repeated.
for(int j=0; j<input.length; j++){
int inputIndex = input[j]-'a';
if(base[inputIndex]==1){
System.out.println(j);
return input[j];
}
}
return '_';
}

Finding the longest string in a 2d array in C

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

Resources