Scan an array using strcmp - c

I'm wondering if there's a way you can scan an array for a match using strcmp. I know the parameters passed to strcmp are C strings. So something like this wouldn't work:
strcmp(arrayofstrings[x], c-string)

It would work as long as the arguments can be reduced to of type const char*.
char *a[] = { "Hello", "Hello" }; // Array of pointers to c strings
if ( !strcmp(a[0],a[1]) ){
// true in this case
}

If you're trying to search the entire array, rather than just comparing two elements, you will need a loop.
const int N = 10;
const char * desired = "desiredString";
char * arrayOfStrings[N];
// You should initialize the elements
// in arrayOfStrings[] before searching
// Searching an unsorted array is O(N)
for(i = 0; i < N; i++)
{
if(strcmp(arrayOfStrings[i], desired) == 0)
{
printf("Found %s.", desired);
break;
}
}

Related

Why the for loop is filling the whole array with the latest string?

Apologies if this is simple, but I am new to C. I am trying to create a loop that fills in an empty array of strings with multiple strings. However, at the end, the whole array is being filled with the latest element ! Below is the code:
int main(void)
{
string array_test[2];
char string_test[300];
for (int i = 0; i < 2; i++)
{
snprintf(string_test, sizeof(string_test),"Test: %i", i);
array_test[i] = string_test;
}
for (int i = 0; i < 2; i++)
{
printf("%s\n", array_test[i]);
}
}
This returns:
Test: 1
Test: 1
But I am expecting:
Test: 0
Test: 1
Because you are using the same buffer to save strings in all iterations. This will make previous strings overwritten by new strings.
Allocate separate buffers for each strings to avoid this.
/* put #include of required headers here */
int main(void)
{
string array_test[2];
char string_test[2][300];
for (int i = 0; i < 2; i++)
{
snprintf(string_test[i], sizeof(string_test[i]),"Test: %i", i);
array_test[i] = string_test[i];
}
for (int i = 0; i < 2; i++)
{
printf("%s\n", array_test[i]);
}
}
Why the for loop is filling the whole array with the latest string?
The for loop is filling the whole array of pointers array_test with the address of the first character of the character array string_test.
That is you declared an array of two pointers
string array_test[2];
and each element of the array points to the first character of the same array string_test
array_test[i] = string_test;
The statement above is equivalent to the following statement
array_test[i] = &string_test[0];
That is an array designator used in expressions with rare exceptions is converted to a pointer to its first element.
So you are outputting the same character array string_test using two pointers.
printf("%s\n", array_test[i]);
Instead of the array of pointers you could declare a two-dimensional character array like
char array_test[2][300];
and in the first for loop you could copy strings formed in the array string_test into elements of the array array_test like
strcpy( array_test[i], string_test );
In this case each element of the two-dimensional array will store its own string.
All elements in the string array point to the same buffer, so they all appear to have the same string, more precisely the value last composed into this buffer.
Using the typedef string for char * creates confusion about this fact, which is one more reason to not hide pointers behind typedefs.
You can allocate a copy of the string in the loop:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *array_test[2];
char string_test[300];
for (int i = 0; i < 2; i++) {
snprintf(string_test, sizeof(string_test), "Test: %i", i);
array_test[i] = strdup(string_test);
}
for (int i = 0; i < 2; i++) {
printf("%s\n", array_test[i]);
}
for (int i = 0; i < 2; i++) {
free(array_test[i]);
}
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 '_';
}

C upper case to lower case

I am having issue with lower casing my words that are being used as inputs. So my program takes in words and sorts them alphabetically and removes duplicates. But I'd like to change words upper case and lower them to equal to lower case words.
example: Apple changes to apple
my input:
./a.out Orange apple banana Apple banana
my output:
Apple
Orange
apple
banana
Here is what I am trying to achieve
output:
apple
banana
orange
Here is my code
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[]) {
int i, j, k, size;
size = argc -1;
char *key;
char* a[argc-1];
for (i = 2; i < argc; i++) {
key = argv[i];
j = i-1;
while (j >= 1 && strcmp(argv[j], key) > 0) {
argv[j+1] = argv[j];
j--;
}
argv[j+1] = key;
}
if (argc > 1){
for (i = 1; i < argc;){
puts(argv[i]);
while (argv[++i] != NULL && strcmp(argv[i - 1], argv[i] ) == 0)
continue;
}
}
return 0;
}
You have a list of words and you want to output them sorted, and only the unique ones. And you want to do it in a case insensitive fashion.
Get all the strings to the same case.
Sort the list of strings.
Don't output repeats.
C has no built in function to lower case a string, but it does have ones to lower case characters: tolower. So we write a function to lower case a whole string by iterating through it and lower casing each character.
void str_lower(char *str) {
for( ; str[0] != NULL; str++ ) {
str[0] = (char)to_lower(str[0]);
}
}
Then we need to sort. That's handled by the built in qsort function. To use it, you need to write a function that compares two strings and returns just like strcmp. In fact, your comparison function will just be a wrapper around strcmp to make qsort happy.
int compare_strings( const void *_a, const void *_b ) {
/* The arguments come in as void pointers to the strings
and must be cast. Best to do it early. */
const char **a = (const char **)_a;
const char **b = (const char **)_b;
/* Then because they're pointers to strings, they must
be dereferenced before being used as strings. */
return strcmp(*a, *b);
}
In order to handle any data type, the comparison function takes void pointers. They need to be cast back into char pointers. And it's not passed the string (char *) it's passed a pointer to the string (char **), again so it can handle any data type. So a and b need to be dereferenced. That's why strcmp(*a, *b).
Calling qsort means telling it the array you want to sort, the number of items, how big each element is, and the comparison function.
qsort( strings, (size_t)num_strings, sizeof(char*), compare_strings );
Get used to this sort of thing, you'll be using it a lot. It's how you work with generic lists in C.
The final piece is to output only unique strings. Since you have them sorted, you can simply check if the previous string is the same as the current string. The previous string is strings[i-1] BUT be sure not to try to check strings[-1]. There's two ways to handle that. First is to only do the comparison if i < 1.
for( int i = 0; i < num_strings; i++ ) {
if( i < 1 || strcmp( strings[i], strings[i-1] ) != 0 ) {
puts(strings[i]);
}
}
Another way is to always output the first string and then start the loop from the second.
puts( strings[0] );
for( int i = 1; i < num_strings; i++ ) {
if( strcmp( strings[i], strings[i-1] ) != 0 ) {
puts(strings[i]);
}
}
This means some repeated code, but it simplifies the loop logic. This trade-off is worth it, complicated loops mean bugs. I botched the check on the first loop myself by writing if( i > 0 && strcmp ... )`.
You'll notice I'm not working with argv... except I am. strings and num_strings are just a bit of bookkeeping so I didn't always have to remember to start with argv[1] or use argv+1 if I wanted to pass around the array of strings.
char **strings = argv + 1;
int num_strings = argc-1;
This avoids a whole host of off-by-one errors and reduces complexity.
I think you can put the pieces together from there.
There are a set of standard functions for checking and changing the type of characters in ctype.h. The one you are interested in is tolower(). You can #include<ctype.h> and then add a snippet like the following to pre-process your argv before doing the sorting:
for(i = 1; i < argc; i++) {
argv[i][0] = tolower(argv[i][0]);
}
That will only operate on the first character of each word. If you need to normalize the entire word:
for(i = 1; i < argc; i++) {
for(j = 0; argv[i][j]; j++) {
argv[i][j] = tolower(argv[i][j]);
}
}
Silly me, I was able to figure it out after looking at my code realizing that i can do key[0] = tolower(key[0]); which i did before having a pointer point at it.
for (i = 2; i < argc; i++) {
key = argv[i];
key[0] = tolower(key[0]);
j = i-1;
while (j >= 1 && strcmp(argv[j], key) > 0) {
argv[j+1] = argv[j];
j--;
}
argv[j+1] = key;
}
Which lower cases the first letter. And if i wanted to lower case all the letters, i would've have used a for loop. Thank you everyone for your contribution. :)

testing for string-equality without the string library

I have code written that I want to see if two char* 'strings' are equal. I have written print statements in the code to help me debug it.
Basically, the commands array is: [a, b, null]
and the cmd the user input can be anything, but if it is a, b, or null then we want to get inside the if statement.
for (i = 0; i < 3; i++){
printf("cmd.name = : %s\nCommand = %s\n", cmd->name, commands[i]);
if (cmd->name == commands[i]){
printf("inside if\n");
valid = 1;
}
}
Its printing out:
cmd.name = : a
Command = a
cmd.name = : a
Command = b
cmd.name = : a
Command = (null)
So in the first instance a should be equal to a right? Why is it not going inside the if statement?
Since you can't use the string library, you will have to implement your own strcmp function.
A char*, as a type, is only a pointer, i.e. it stores an address. Then the simple '==' will compare addresses, which is not what you want.
A simple strcmp function can be:
int myStrcmp(const char *str1, int size1, const char *str2, int size2)
{
int i = 0;
if(size1 != size2)
return -1 //different strings
for(i = 0; i < size1; i++)
{
if(str1[i] != str2[i])
return -1; //different strings
}
return 0; //same strings
}
The trick here is that you have to know somehow what are the string sizes. If you can't use the string library, I imagine you can't use strlen() as well.
The char* represent a pointer to the first character of a string, so by testing cmd->name == commands[i] you test if name has the same address as commands[i]. To compare two strings you can use the strcmp function of the standard library (string.h) and if the function return 0 your two strings are equal.
Edit : If you can't use the string library then write a simple loop. During your loop, if you find a character different between the two strings you return a wrong value (by example 0) and if you can go to the end of your strings without finding differents characters then you return a true value (by example 1)

How to find the length of an integer array passed as an argument in c?

I need to calculate the length of passed array in monkey method. How to do so, as input decays to a pointer inside monkey method...?
int monkey(int input1[])
{
//Write code here
}
Constraints:
1) You are not allowed to change the function signature.
int monkey(int input1[], size_t arraySize)
{
}
Passing the size of the array is the most usual method.
Alternatively you can do something like C strings, and add a sentinel value to the end of your array (max value, 0, -1, etc) and count the number of elements before this sentinel value.
There are no other alternatives I can think of.
In the general case, you don't. As it's just a pointer, information about the array is not available.
So you should pass in a size, or wrap it in a struct that contains the size.
Or as it's an array of int, you could use the first value in the array as the size.
Alternatively, depending on your use-case, you could zero-terminate (or else unambiguously mark the end of) the data in the array.
There is no way to do such thing in C. The definition of your function
int monkey(int input[])
is formally equivalent to
int monkey(int *input)
so you ALWAYS need to pass the length of your array as an additional parameter
Two options:
int array[10+1];
array[0] = 10;
// fill in the rest in array[1...10]
monkey(array);
// monkey() checks input1[0] to see how many data elements there are
and
int array[10+1];
array[0] = 10;
// fill in the rest in array[1...10]
monkey(array + 1);
// monkey() checks input1[-1] to see how many data elements there are
Alternatively, you can pass the size/count via a different channel, for example, a global variable, which you may guard with a critical section or a semaphore/lock if necessary.
When you pass the array to the function, you can store the length as the first element of the array:
int monkey(int input1[])
{
int len = input1[0];
for (int i = 1; i < len; ++i) {
// do something with the array
}
}
//...
int array[20];
array[0] = 20;
monkey(array);
An alternative method is to do it using pointer arithmetics instead, so that the function can treat the array as starting from 0:
int monkey(int input1[])
{
int len = *(input1 - 1);
for (int i = 0; i < len; ++i) {
// do something with the array
}
}
//...
int array[20];
array[0] = 19;
monkey(array + 1);
But it's the same thing really. The only advantage this has is guarding against mistakes like starting from 0 instead of 1. But then this means that you could forget to pass array + 1 when you call it. So meh.
int main()
{
int arr[] = { 62,34,4,4,4,3,2,-1 };
monkey(arr);
return 0;
}
int monkey(int input1[])
{
int n = 0;
while (a[n] != -1)
{
n++;
}
printf_s("Length of input1[] is: %d", n);
return n;
}
int monkey(int input1[])
{
//Write code here
}
int len = sizeof(input1)/sizeof(input1[0]);
OR
int len = sizeof(input1)/sizeof(int);
is WRONG..
IT will always give 2..as input1 is a LONG POINTER AND so size is 8,,and sizeof(int) is 4..
if you want to find the length there is 2 ways...
1) pass the length...
( you cannot i suppose )
2) if you have idea..about the input1 array...say ( TECH GIG competition )
try to find out the number contained in the undefined parts of the array..
say here i found out for the sample ..{1,2,3,4,5} => input1[6] => contains the number -9999
so just wrote a while loop to find the length
while(input1[len]!=-9999)
len++;
to find out that
input1[6] => contains the number -9999
i use in the answer
return input1[6]..to check
that -9999 was the answer
i just submitted the answer for TECH GIG competition

Resources