Here is the problem we have to check if two strings contain the same characters, regardless of order. For example s1=akash s2=ashka match.
My program is showing NO for every input strings;
s1 and s2 are two input strings
t is the number of testcases
->it would be really helpful if you can tell me where is the error I am a beginner
#include<stdio.h>
#include<string.h>
int main(){
int t,i,j;
scanf("%d",&t);
while(t>0){
char s1[100],s2[100];
scanf("%s ",s1);
scanf("%s",s2);
int count=0;
int found[100];
for(i=0;i<strlen(s1)-1;i++){
for(j=0;j<strlen(s1);j++){
if(s1[i]==s2[j]){
found[i]=1;
break;
}
}
}
for(i=0;i<strlen(s1);i++){
if(found[i]!=1){
count=1;
break;
}
}
if(count==1)
printf("NO");
else
printf("YES");
t--;
}
}
Some good answers above suggest sorting the strings first.
If you want to modify your program above to do this job then you need to modify it as you realised. I have a suggestion (in words) for how to do this below - after that there is a modified code that works, and finally a couple of extra points.
I guess that two strings aa and a would not be equal according to your definition, but your program would say that they were equal because once you find a character you do not have anyway of saying that it has been 'used up'
I would suggest that you change your found[] array so that it records when a character in the second string is matched.
I suggest logic as follows.
Loop through all S1 characters
| Loop through S2 charaters
| - if you get a match mark the S2 character as found
| - if you don't get a match by the end of the S2 loops then you are done - they are not equal
At the end of the S1 loop if you have not finished early then every character is matched, but you need to go through found[] array to check that every character in S2 was found.
working code is below....
note
you did not initialize found - it is initialize below in code
the first loop needs to have < strlen(s1) not < strlen(s1)-1
the second loop you should have been going to strlen(s2).
logic changed as described above so that found records characters found in s2 not s1
logic also changed so that if a character in s1 is not found the loop breaks early. There are tests to see if the loop broke early to see if the values of i and j are what we expect at the end of the loop.
edited code below (at the bottom below the code are some extra comments)
#include<stdio.h>
#include<string.h>
int main(){
int t,i,j;
scanf("%d",&t);
while(t>0){
char s1[100],s2[100];
scanf("%s ",s1);
scanf("%s",s2);
int count=0;
int found[100]={ 0 };
for(i=0;i<strlen(s1);i++){
for(j=0;j<strlen(s2);j++){
if(found[j]==1) continue; // character S2[j] already found
if(s1[i]==s2[j]){
found[j]=1;
break;
}
}
if (j==strlen(s2)) {
break; // we get here if we did not find a match for S1[i]
}
}
if (i!=strlen(s1)) {
printf("NO"); // we get here if we did not find a match for S1[i]
}
else {
// matched all of S1 now check S2 all matched
for(i=0;i<strlen(s2);i++){
if(found[i]!=1){
count=1;
break;
}
}
if(count==1) {
printf("NO");
}
else {
printf("YES");
}
}
t--;
}
return 0;
}
Two extra points to make your code more efficient.
First, as suggested by #chux it will probably be faster not to have strlen(s2) in the condition for the loop. What you could have instead would be for (j=0;s2[j];j++). This works because the final character at the end of the string will have the value 0 and in C a value of 0 means false.. in the for loop the loop runs whilst the logic statement is true and when it is false the loop stops. The speed up of not using strlen[s2] in the loop is because the compiler might decide to calculate strlen[s2] each time you go through the loop, which means counting for l2 if l2 is the length of s2 - thus as you have to go through the two loops l1*l2 times potentially with the strlen counting you actually have l1*l2*l2 steps.
secondly, you could speed up many tests by checking to see if the lengths of the two strings are different before checking if they contain the same number of the same types of character.
As suggested in my comment, and since it's now a bit more clear, an easy way to compare two multisets represented as strings is to:
Sort the two strings (easy using the qsort() standard function)
Compare the result (using the strcmp() standard function)
This will work since it will map both "akash" and "ashka" to "aahks", before comparing.
Sort both the strings by using bubble sort or any other tech. you know , then simply compair both strings by using strcmp() function .
for(i=0;i<strlen(s1)-1;i++){
for(j=0;j<strlen(s1);j++){
if(s1[i]==s2[j]){
found[i]=1;
break;
}
}
}
I am not able to understand why are you using j<strlen(s1) is second loop.
I think simple solution will be sorting the characters alphabetically and comparing one by one in single loop.
First, note that found is never initialized. The values within it are unknown. It ought to be initialized by setting every element to zero before each test for equality. (Or, if not every element, every element up to strlen(s1)-1, as those are the ones that will be used.)
Once found is initialized, though, there is another problem.
The first loop on i uses for(i=0;i<strlen(s1)-1;i++). Within this, found[i] is set if a match is found to s1[i]. Note that i never reaches strlen(s1)-1 within the loop, since the loop terminates when it does.
The second loop on i uses for(i=0;i<strlen(s1);i++). Within this loop, found[i] is tested to see if it is set. Note that i does reach strlen(s1)-1, since the loop terminates only when i reaches strlen(s1). However, found[strlen(s1)-1] can never have been set by the first loop, since i never reaches strlen(s1)-1 in the first loop. Therefore, the second loop would always report failure.
Additionally, it is not clear whether two strings ought to be considered equal if and only if they are anagrams (the characters in one can be rearranged to form the other string, without adding or removing any characters) or if each character in one string is found at least once in the other (“aaabbc” would be equal to “abbccc”, because both strings contain a, b, and c).
As written, with the initialization and loop bugs fixed, your program tests whether each character in the first string appears in the second string. This is not an equivalence relation because it is not reflexive: It does not test whether each character in the second string appears in the first string. So, you need to think more about what property you want to test and how to test for it.
Complicated solutions I did as a training. Two implementations controlled with a macro below.
First implementation loops through every character in the string, counts it's count in the first and second string and compares the values.
The second implementation allocates and creates a map of characters with count for each string and then compares these maps.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
// configuration
#define STRCHARSETCNTCMP_METHOD_FOREACH 0
#define STRCHARSETCNTCMP_METHOD_MAP 1
// eof configuration
//#define dbgln(fmt, ...) fprintf(stderr, "%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
#define dbgln(...) ((void)0)
/**
* STRing CHARacter SET CouNT CoMPare
* compare the count of set of characters in strings
* #param first string
* #param the other string
* #ret true if each character in s1 is used as many times in s2
*/
bool strcharsetcntcmp(const char s1[], const char s2[]);
// Count how many times the character is in the string
size_t strcharsetcntcmp_count(const char s[], char c)
{
assert(s != NULL);
size_t ret = 0;
while (*s != '\0') {
if (*s == c) {
++ret;
}
*s++;
}
return ret;
}
// foreach method implementation
bool strcharsetcntcmp_method_foreach(const char s1[], const char s2[])
{
const size_t s1len = strlen(s1);
const size_t s2len = strlen(s2);
if (s1len != s2len) {
return false;
}
for (size_t i = 0; i < s1len; ++i) {
const char c = s1[i];
const size_t cnt1 = strcharsetcntcmp_count(s1, c);
const size_t cnt2 = strcharsetcntcmp_count(s2, c);
// printf("'%s','%s' -> '%c' -> %zu %zu\n", s1, s2, c, cnt1, cnt2);
if (cnt1 != cnt2) {
return false;
}
}
return true;
}
// array of map elements
struct strcharsetcntcmp_map_s {
size_t cnt;
struct strcharsetcntcmp_map_cnt_s {
char c;
size_t cnt;
} *map;
};
// initialize empty map
void strcharsetcntcmp_map_init(struct strcharsetcntcmp_map_s *t)
{
assert(t != NULL);
dbgln("%p", t);
t->map = 0;
t->cnt = 0;
}
// free map memory
void strcharsetcntcmp_map_fini(struct strcharsetcntcmp_map_s *t)
{
assert(t != NULL);
dbgln("%p %p", t, t->map);
free(t->map);
t->map = 0;
t->cnt = 0;
}
// get the map element for character from map
struct strcharsetcntcmp_map_cnt_s *strcharsetcntcmp_map_get(const struct strcharsetcntcmp_map_s *t, char c)
{
assert(t != NULL);
for (size_t i = 0; i < t->cnt; ++i) {
if (t->map[i].c == c) {
return &t->map[i];
}
}
return NULL;
}
// check if the count for character c was already added into the map
bool strcharsetcntcmp_map_exists(const struct strcharsetcntcmp_map_s *t, char c)
{
return strcharsetcntcmp_map_get(t, c) != NULL;
}
// map element into map, without checking if it exists (only assertion)
int strcharsetcntcmp_map_add(struct strcharsetcntcmp_map_s *t, char c, size_t cnt)
{
assert(t != NULL);
assert(strcharsetcntcmp_map_exists(t, c) == false);
dbgln("%p %p %zu %c %zu", t, t->map, t->cnt, c, cnt);
void *pnt = realloc(t->map, sizeof(t->map[0]) * (t->cnt + 1));
if (pnt == NULL) {
return -errno;
}
t->map = pnt;
t->map[t->cnt].c = c;
t->map[t->cnt].cnt = cnt;
t->cnt++;
return 0;
}
// create map from string, map needs to be initialized by init and needs to be freed with fini
int strcharsetcntcmp_map_parsestring(struct strcharsetcntcmp_map_s *t, const char s[])
{
assert(t != NULL);
assert(s != NULL);
int ret = 0;
while (*s != '\0') {
const char c = *s;
if (!strcharsetcntcmp_map_exists(t, c)) {
const size_t cnt = strcharsetcntcmp_count(s, c);
ret = strcharsetcntcmp_map_add(t, c, cnt);
if (ret != 0) {
break;
}
}
++s;
}
return ret;
}
// compare two maps if they have same sets of characters and counts
bool strcharsetcntcmp_cmp(const struct strcharsetcntcmp_map_s *t, const struct strcharsetcntcmp_map_s *o)
{
assert(t != NULL);
assert(o != NULL);
if (t->cnt != o->cnt) {
return false;
}
for (size_t i = 0; i < t->cnt; ++i) {
const char c = t->map[i].c;
const size_t t_cnt = t->map[i].cnt;
struct strcharsetcntcmp_map_cnt_s *o_map_cnt = strcharsetcntcmp_map_get(o, c);
if (o_map_cnt == NULL) {
dbgln("%p(%zu) %p(%zu) %c not found", t, t->cnt, o, o->cnt, c);
return false;
}
const size_t o_cnt = o_map_cnt->cnt;
if (t_cnt != o_cnt) {
dbgln("%p(%zu) %p(%zu) %c %zu != %zu", t, t->cnt, o, o->cnt, c, t_cnt, o_cnt);
return false;
}
dbgln("%p(%zu) %p(%zu) %c %zu", t, t->cnt, o, o->cnt, c, t_cnt);
}
return true;
}
// map method implementation
bool strcharsetcntcmp_method_map(const char s1[], const char s2[])
{
struct strcharsetcntcmp_map_s map1;
strcharsetcntcmp_map_init(&map1);
if (strcharsetcntcmp_map_parsestring(&map1, s1) != 0) {
abort(); // <insert good error handler here>
}
struct strcharsetcntcmp_map_s map2;
strcharsetcntcmp_map_init(&map2);
if (strcharsetcntcmp_map_parsestring(&map2, s2) != 0) {
abort(); // <insert good error handler here>
}
const bool ret = strcharsetcntcmp_cmp(&map1, &map2);
strcharsetcntcmp_map_fini(&map1);
strcharsetcntcmp_map_fini(&map2);
return ret;
}
bool strcharsetcntcmp(const char s1[], const char s2[])
{
assert(s1 != NULL);
assert(s2 != NULL);
#if STRCHARSETCNTCMP_METHOD_FOREACH
return strcharsetcntcmp_method_foreach(s1, s2);
#elif STRCHARSETCNTCMP_METHOD_MAP
return strcharsetcntcmp_method_map(s1, s2);
#endif
}
// unittests. Should return 0
int strcharsetcntcmp_unittest(void)
{
struct {
const char *str1;
const char *str2;
bool eq;
} const tests[] = {
{ "", "", true, },
{ "a", "b", false, },
{ "abc", "bca", true, },
{ "aab", "abb", false, },
{ "aabbbc", "cbabab", true, },
{ "123456789012345678901234567890qwertyuiopqwertyuiopasdfghjklasdfghjklzxcvbnmzxcvbnm,./;", "123456789012345678901234567890qwertyuiopqwertyuiopasdfghjklasdfghjklzxcvbnmzxcvbnm,./;", true },
{ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", true },
{ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900", false },
};
int ret = 0;
for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
const bool is = strcharsetcntcmp(tests[i].str1, tests[i].str2);
if (is != tests[i].eq) {
fprintf(stderr,
"Error: strings '%s' and '%s' returned %d should be %d\n",
tests[i].str1, tests[i].str2, is, tests[i].eq);
ret = -1;
}
}
return ret;
}
int main()
{
return strcharsetcntcmp_unittest();
}
I've got an issue i can't handle so i've thought maybe you can help me. Basically i have a function that receives a char* as a paramater and does some stuff to it(i've checked those steps/functions and they work just fine).If the char* given in the function is ""(i guess NULL), i receive seg fault with assert.
Here is the code:
char *computeRNA(char *s)
{
if (s != NULL && s!= "")
{
Lista* l = to_list(s);
int i;
l = l->next;
for(i = 0; i<= lungime(l); ++i)
{
if(l->info == 'T')
l->info = 'U';
l = l->next;
}
char *rna = to_pointer(l);
return rna;
}
return NULL;
}
And here is the assert:
char *s;
s = computeRNA("");
ASSERT(!strcmp(s, ""), "computeRNA-01");
free(s);
This is a school homework so i can not change assert's code , only the function.Thanks in advance !
This ASSERT that you weren't supposed to be changing, tests that if an empty string is given to computeRNA it should also return an empty string:
s = computeRNA("");
ASSERT(!strcmp(s, ""), "computeRNA-01");
Your code returns null pointer. Also comparing strings needs to be done using strcmp, s == "" would only compare pointer values that wouldn't be of use here.
Thus I'd start the function with
// null pointer was given
if (!s) {
return calloc(1, 1);
}
// an empty string was given (the first character pointed to b s is the string terminator.)
// to compare explicitly, you need to do `strcmp(s, "")` == 0. `s == ""` is wrong.
if (!*s) {
return "";
}
You cannot pass a NULL pointer to strcmp() as argument. Before the ASSERT statement, just check for non-NULL value of s. Something like
if (s) {
ASSERT(!strcmp(s, ""), "computeRNA-01");
}
should do the job.
EDIT:
In case changing the function using the assertion is also not possible, you can modify the computeRNA() function to return an empty string, instead of NULL, like
char * empty_string = calloc(1,1);
return empty_string;
which can later be passed to free() in the caller.
How do we return a string from a function?
I'm just beginning to learn to use the string functions and malloc, basically, i'm trying to get:
ef = 11101111
as an output.
Here's what i've tried.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
const int MAXWORD = 2;
char hexToBinary(char hex[MAXWORD]);
int main()
{
char hex[MAXWORD] = {'e','f'};
printf("%s = %s\n", hex, hexToBinary(hex));
return 0;
}
char hexToBinary(char hex[MAXWORD])
{
char *hexToBn = malloc( (MAXWORD-1) * sizeof(char) );
char *convertedString = malloc( (MAXWORD-1) * sizeof(char) );
for(int i=0 ; i<MAXWORD ; ++i)
{
if(hex[i] == 'e' || hex[i] == 'E')
{
strcpy(hexToBn, "1110");
}
if(hex[i] == 'f' || hex[i] == 'F')
{
strcpy(hexToBn, "1111");
}
strcat(convertedString, hexToBn);
}
return convertedString;
}
If you would like to make a function that returns a C string, declare it returning char*:
char *hexToBinary(char hex[MAXWORD]) {
...
}
This is not ideal, because it creates a possibility of a memory leak. In fact, your code would leak a string, because you never free what's allocated in malloc.
You should either fix the leak by capturing the return value and calling free once you are done with it, or use the buffer+length API pattern:
char *bin = hexToBinary(hex);
printf("%s = %s\n", hex, bin);
free(bin);
An alternative API would look like this:
void hexToBinary(char hex[], char bin[], int len) {
... // Users pass the output buffer bin and its length len
}
Couple ways to do so:
1: Allocate string on the heap and pass it to the caller. The caller ensures the string is delete using free.
char * get_str()
{
char * str = malloc(string_length + 1);
// Do something
return str;
}
2: pass the string to the function
void update_string(char * input, int length)
{
// modify string
}
Declare the return type as char*. Then use it like you would.
Note: you may have to do other things to your code. I just said the first thing I saw at a glance. Also, you need to make sure that your memory is deallocated with free when you are done with it.
I'm trying to make a quick function that gets a word/argument in a string by its number:
char* arg(char* S, int Num) {
char* Return = "";
int Spaces = 0;
int i = 0;
for (i; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
//Want to append S[i] to Return here.
}
else if (Spaces > Num) {
return Return;
}
}
printf("%s-\n", Return);
return Return;
}
I can't find a way to put the characters into Return. I have found lots of posts that suggest strcat() or tricks with pointers, but every one segfaults. I've also seen people saying that malloc() should be used, but I'm not sure of how I'd used it in a loop like this.
I will not claim to understand what it is that you're trying to do, but your code has two problems:
You're assigning a read-only string to Return; that string will be in your
binary's data section, which is read-only, and if you try to modify it you will get a segfault.
Your for loop is O(n^2), because strlen() is O(n)
There are several different ways of solving the "how to return a string" problem. You can, for example:
Use malloc() / calloc() to allocate a new string, as has been suggested
Use asprintf(), which is similar but gives you formatting if you need
Pass an output string (and its maximum size) as a parameter to the function
The first two require the calling function to free() the returned value. The third allows the caller to decide how to allocate the string (stack or heap), but requires some sort of contract about the minumum size needed for the output string.
In your code, when the function returns, then Return will be gone as well, so this behavior is undefined. It might work, but you should never rely on it.
Typically in C, you'd want to pass the "return" string as an argument instead, so that you don't have to free it all the time. Both require a local variable on the caller's side, but malloc'ing it will require an additional call to free the allocated memory and is also more expensive than simply passing a pointer to a local variable.
As for appending to the string, just use array notation (keep track of the current char/index) and don't forget to add a null character at the end.
Example:
int arg(char* ptr, char* S, int Num) {
int i, Spaces = 0, cur = 0;
for (i=0; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
ptr[cur++] = S[i]; // append char
}
else if (Spaces > Num) {
ptr[cur] = '\0'; // insert null char
return 0; // returns 0 on success
}
}
ptr[cur] = '\0'; // insert null char
return (cur > 0 ? 0 : -1); // returns 0 on success, -1 on error
}
Then invoke it like so:
char myArg[50];
if (arg(myArg, "this is an example", 3) == 0) {
printf("arg is %s\n", myArg);
} else {
// arg not found
}
Just make sure you don't overflow ptr (e.g.: by passing its size and adding a check in the function).
There are numbers of ways you could improve your code, but let's just start by making it meet the standard. ;-)
P.S.: Don't malloc unless you need to. And in that case you don't.
char * Return; //by the way horrible name for a variable.
Return = malloc(<some size>);
......
......
*(Return + index) = *(S+i);
You can't assign anything to a string literal such as "".
You may want to use your loop to determine the offsets of the start of the word in your string that you're looking for. Then find its length by continuing through the string until you encounter the end or another space. Then, you can malloc an array of chars with size equal to the size of the offset+1 (For the null terminator.) Finally, copy the substring into this new buffer and return it.
Also, as mentioned above, you may want to remove the strlen call from the loop - most compilers will optimize it out but it is indeed a linear operation for every character in the array, making the loop O(n**2).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *arg(const char *S, unsigned int Num) {
char *Return = "";
const char *top, *p;
unsigned int Spaces = 0;
int i = 0;
Return=(char*)malloc(sizeof(char));
*Return = '\0';
if(S == NULL || *S=='\0') return Return;
p=top=S;
while(Spaces != Num){
if(NULL!=(p=strchr(top, ' '))){
++Spaces;
top=++p;
} else {
break;
}
}
if(Spaces < Num) return Return;
if(NULL!=(p=strchr(top, ' '))){
int len = p - top;
Return=(char*)realloc(Return, sizeof(char)*(len+1));
strncpy(Return, top, len);
Return[len]='\0';
} else {
free(Return);
Return=strdup(top);
}
//printf("%s-\n", Return);
return Return;
}
int main(){
char *word;
word=arg("make a quick function", 2);//quick
printf("\"%s\"\n", word);
free(word);
return 0;
}
char* clean_string (char *input_string){
/*Ensure that input string isn't null and only do heavy lifting if it's not null*/
if (input_string){
char *stripped;
stripped = (char*)malloc(strlen(input_string)*sizeof(char));
while (*input_string != '\0'){
if isalpha(*input_string){
*stripped = toupper(*input_string);
input_string++;
stripped++;
} else {
input_string++;
}
}
/* *stripped++ += '\0';*/
return stripped;
}
/*default return val*/
return NULL;
}
Can anybody tell me where I'm going wrong with this? Tried to do a test run and it doesn't output anything when I try to call it.
You are returning a pointer to the last character in the string (stripped++ ?).
You are allocating one byte too few (should be strlen(...) + 1).
stripped = (char*)malloc(strlen(input_string)*sizeof(char)); /* Wrong. */
stripped = (char*)malloc(strlen(input_string) + 1);
/* .. */
stripped++;
/* .. */
return stripped;
Try to keep a copy, something like original_stripped = stripped before starting to change stripped, and return the copied value (not the incremented one).
The problem is with calling stripped++. You are modifying the pointer you get by malloc. Make an extra pointer char *result_char = stripped; and use that for iteration over resulting string.
The problem ís that you increment your stripped variable before returning it.
Try:
char *stripped;
char *result;
stripped = (char*)malloc(strlen(input_string)*sizeof(char));
result = stripped;
...
return result;
How about just:
char* clean_string (char *input_string)
{
/*Ensure that input string isn't null and only do heavy lifting if it's not null*/
if (input_string)
{
char *stripped;
int i;
stripped = (char*)malloc(strlen(input_string)*sizeof(char) + 1);
for(i=0; i < strlen(input_string); i++)
stripped[i] = (isalpha(input_string[i]) ? toupper(input_string[i]) : input_string[i]);
return stripped;
}
/*default return val*/
return NULL;
}