I have the following function, and I want to test if the two strings are anagrams. One way I thought about doing it would be to sum the values of each of the characters in the strings and then compare their values.
However, I am getting a segmentation fault in both the for loops when I try to run my program. I am not understanding this correctly, is there anything I am doing incorrectly in my code?
int anagram(char *a, char *b)
{
int sum1 = 0;
int sum2 = 0;
char *p, *q;
for (p=a; p != '\0'; p++) {
sum1 += *p - 'a';
}
for (q=b; q != '\0'; q++) {
sum2 += *q - 'a';
}
if ( sum1 == sum2 )
return 1;
else
return 0;
}
In your for loops you must check
*p != '\0'
*q != '\0'
This is the cause of the seg-fault.
Furthermore, even fixed, that code will give you false positives:
"bc" anagram of "ad"
I suggest you a different approach:
make two arrays of ints sized 256, zero initialized.
Let every item of each array keep the count of every letter (char) of each string.
Finally compare if the two arrays are the same.
I leave the task of writig the code to you.
"p !=0" should be "*p != 0", as it is now you are waiting for the pointer to become null.
Since we're already giving answers about better approaches, here's mine:
Get a list of (preferably small) prime numbers. You need one for every possible character of your input strings, thus when you want to check strings containing only digits 0 to 9 you need 10 prime numbers. Let's take these:
static unsigned const primes[10] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
Now, since each number has exactly one prime factorisation, and because of multiplication being commutative, you can just build the product of the prime numbers for each character of your string. If they're identical, then for each character holds that it has been the same number of times in both strings. Thus, both strings are anagrams of each other.
unsigned long prime_product(char const * str) {
assert(str != NULL);
unsigned long product = 1;
for (; *str != '\0'; ++str) {
assert(*str >= '0');
assert(*str <= '9');
product *= primes[*str - '0'];
}
return product;
}
char is_anagram(char const * one, char const * two) {
return prime_product(one) == prime_product(two);
}
This should even work to some extend when the product overflows, though then false positives are possible (though their likelihood can be greatly reduced when also comparing the length of the two strings).
As can be seen this version has O(n) time and constant space complexity.
Here is a complete solution for your problem:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmp(const void *str1, const void *str2) {
return (*((char*)str1) - *((char*)str2));
}
bool areAnagram(char *str1, char *str2) {
int n1 = strlen(str1);
int n2 = strlen(str2);
if (n1 != n2)
return false;
qsort(str1, n1, 1, &cmp);
qsort(str2, n2, 1, &cmp);
for (int i = 0; i < n1; i++)
if (str1[i] != str2[i])
return false;
return true;
}
int main()
{
char str1[] = "test";
char str2[] = "tset";
if (areAnagram(str1, str2))
printf("The two strings are anagram of each other");
else
printf("The two strings are not anagram of each other");
return 0;
}
Related
I tried to write a function to convert a string to an int:
int convert(char *str, int *n){
int i;
if (str == NULL) return 0;
for (i = 0; i < strlen(str); i++)
if ((isdigit(*(str+i))) == 0) return 0;
*n = *str;
return 1;
}
So what's wrong with my code?
*n = *str means:
Set the 4 bytes of memory that n points to, to the 1 byte of memory that str points to. This is perfectly fine but it's probably not your intention.
Why are you trying to convert a char* to an int* in the first place? If you literally just need to do a conversion and make the compiler happy, you can just do int *foo = (int*)bar where bar is the char*.
Sorry, I don't have the reputation to make this a comment.
The function definitely does not perform as intended.
Here are some issues:
you should include <ctype.h> for isdigit() to be properly defined.
isdigit(*(str+i)) has undefined behavior if str contains negative char values. You should cast the argument:
isdigit((unsigned char)str[i])
the function returns 0 if there is any non digit character in the string. What about "-1" and "+2"? atoi and strtol are more lenient with non digit characters, they skip initial white space, process an optional sign and subsequent digits, stopping at the first non digit.
the test for (i = 0; i < strlen(str); i++) is very inefficient: strlen may be invoked for each character in the string, with O(N2) time complexity. Use this instead:
for (i = 0; str[i] != '\0'; i++)
*n = *str does not convert the number represented by the digits in str, it merely stores the value of the first character into n, for example '0' will convert to 48 on ASCII systems. You should instead process every digit in the string, multiplying the value converted so far by 10 and adding the value represented by the digit with str[i] - '0'.
Here is a corrected version with your restrictive semantics:
int convert(const char *str, int *n) {
int value = 0;
if (str == NULL)
return 0;
while (*str) {
if (isdigit((unsigned char)*str)) {
value = value * 10 + *str++ - '0';
} else {
return 0;
}
}
*n = value;
return 1;
}
conversion of char* pointer to int*
#include
main()
{
char c ,*cc;
int i, *ii;
float f,*ff;
c = 'A'; /* ascii value of A gets
stored in c */
i=25;
f=3.14;
cc =&c;
ii=&i;
ff=&f;
printf("\n Address contained
in cc =%u",cc);
printf("\n Address contained
in ii =%u",ii);
printf(:\n Address contained
in ff=%u",ff);
printf(\n value of c= %c",
*cc);
printf(\n value of i=%d",
**ii);
printf(\n value of f=%f",
**ff);
}
I found this example
int SizeofCharArray(char *phrase)
{
int size = 0;
int value = phrase[size];
while(value != 0)
{
value = phrase[size];
size++;
};
//printf("%i%s", size, "\n");
return size;
}
here
But how can I count number of letters in string array using pure C? Even I do not understand how can I initialize string array?!
Thank you!
The posted code is of rather poor quality. The name of the function, SizeofCharArray, does not match the description, count number of letters in string array.
If you want to return the number of characters in the array, use:
int SizeofCharArray(char *phrase)
{
int size = 0;
char* cp = phrase;
while( *cp != '\0')
{
size++;
cp++;
};
return size;
}
If you want to return the number of letters in the array, use:
int isLetter(char c)
{
return (( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ));
}
int GetNumberOfLetters(char *phrase)
{
int num = 0;
char* cp = phrase;
while( *cp != '\0')
{
if ( isLetter(*cp) )
{
num++;
}
cp++;
};
return num;
}
This will count the number of alphabetic characters in a c-string:
#include <ctype.h>
int numberOfLetters(char *s)
{
int n = 0;
while (*s)
if (isalpha(*s++))
n++;
return n;
}
If you want the actual number of characters, counting characters like spaces and numbers, just use strlen(s) located in string.h.
To find the length of C string, you can use strlen() function
#include<string.h>
char str[]="GJHKL";
const char *str1="hhkjj";
int len1=strlen(str)<<"\n";
int len2=strlen(str1);
It's not particularly good C. I doesn't give you the size of a char array -- that's impossible to determine if you've lost that information. What it does give you is the size of a null-terminated char array (AKA a c-string), and it does so by counting the characters until it finds the null-terminator (0 byte or '\n'). As a matter of fact, what you've got up top is a not particularly good strlen implementation (strlen is a standard library function that does the same thing -- determine the size of a null-terminated char array)
I believe this below should be a little more C-ish implementation of the same thing:
size_t strlen(const char *s){
const char* ptr = s;
for(; *ptr; ++ptr); //move the pointer until you get '\0'
return ptr-s; //return the difference from the original position (=string length;)
}
It returns size_t (64 bit unsigned int if you're on a 64 bit machine and 32 on 32 machines, so it will work on arbitrarily long strings as long as they fit into memory) and it also declares that it won't modify the array it measures (const char *s means a pointer you promise not to use to change what it points to).
I am doing a check whether 2 strings are permutations. I sort the strings then compare each character to each other. However, I think my sorting process also changes the original strings (I am very bad with pointers and passing by reference).
Is there a way to check without modifying the original strings?
I also tried using strcpy but I don't really know how to use it.
I tried this in my check() function:
char temp[128];
strcpy(temp, word);
Below is my code. I call the areAnagram function from another function like this:
void check(char *word, struct Entry *en) {
if (areAnagram(en->word, word) == 1) {
//printf("EW:%s W:%s\n", en->word, word);
//For example, this should return something like
// EW:silent W:listen
//But I got
// EW:eilnst W:eilnst
}
}
Structure for Entry:
typedef struct Entry {
char *word;
int len;
struct Entry *next;
} Entry;
Here is the anagram check process:
void quickSort(char *arr, int si, int ei);
int areAnagram(char *str1, char *str2)
{
// Get lenghts of both strings
int n1 = strlen(str1);
int n2 = strlen(str2);
// If lenght of both strings is not same, then they cannot be anagram
if (n1 != n2) {
return 0;
}
// Sort both strings
quickSort (str1, 0, n1 - 1);
quickSort (str2, 0, n2 - 1);
int i;
// Compare sorted strings
for (i = 0; i < n1; i++) {
if (str1[i] != str2[i]) {
return 0;
}
}
return 1;
}
void exchange(char *a, char *b)
{
char temp;
temp = *a;
*a = *b;
*b = temp;
}
int partition(char A[], int si, int ei)
{
char x = A[ei];
int i = (si - 1);
int j;
for (j = si; j <= ei - 1; j++) {
if(A[j] <= x) {
i++;
exchange(&A[i], &A[j]);
}
}
exchange (&A[i + 1], &A[ei]);
return (i + 1);
}
void quickSort(char A[], int si, int ei)
{
int pi; /* Partitioning index */
if(si < ei) {
pi = partition(A, si, ei);
quickSort(A, si, pi - 1);
quickSort(A, pi + 1, ei);
}
}
There is a better way of checking whether two strings are anagrams.You can create an array to store the count of each character in first string(increment the ASCII value index in the array). Then traverse second string and decrement the count of each character (ASCII value index in the array). Now check if all elements of array are zero,if yes these are anagrams otherwise not.
int arr[123];
suppose two strings are s1="abba" and s2="baba"
while traversing first string arr[97]=2,arr[98]=2;
while traversing second array arr[97]=0,arr[98]=0;
Now if you traverse the whole array then all elements will be zero.
But if two strings s1="abba" and s2="abac"
while traversing first string arr[97]=2,arr[98]=2;
while traversing second string arr[97]=0,arr[98]=1,arr[99]=-1;
Since all elements of array are not zero so these are not anagrams.
The complexity of above algorithm is O(n).
Hope it helps.
Make a copy using strcpy:
char *copy = malloc(strlen(word) + 1); // can use a temporary buffer, but this allows variable length inputs
strcpy(copy, word);
// use copy as your temporary string
free(copy);
Your title states that you do not want to modify the original string, however your solution uses Quicksort, which modifies the string. Plus, sorting -- even a fast optimized sort -- is an expensive operation and is not needed for the problem you are trying to solve. You could use a lookup table for speed and it would not modify the original string. You simply create a unique number for each letter and sum the values. Equal sums would constitute an anagram.
/* OPTION 1: let the compiler build your table */
static const int A=0x0000001;
static const int B=0x0000002;
static const int C=0x0000004;
/* continue to double for other letters until ... */
static const int Z=0x4000000;
/* OPTION 2: calculate a cheap hash for each letter */
/* Returns 0 for anagram similar to strcmp */
int anagram (const char* word1, const char* word2)
{
/* strings must be equal length */
if (strlen(word1) != strlen(word2))
return -1;
unsigned long sum1 = 0;
unsigned long sum2 = 0;
char c;
for (int i = 0 ; word1[i] != '\0' ; i++)
{
/* use toupper() function here if case insensitive */
c = toupper(word1[i]);
sum1 += 1 << (c - 'A');
}
for (int i = 0 ; word2[i] != '\0' ; i++)
{
/* use toupper() function here if case insensitive */
c = toupper(word2[i]);
sum2 += 1 << (c - 'A');
}
return (int)(sum1 - sum2); /* ignore overflow */
}
The anagram function above is untested and has been written for clarity. You'd need to include the ctype.h to convert the case using toupper().
Finally, you could make a copy of one of the strings, traverse the other string calling strchr() on each character to find the matching character in the copy. If strchr() returns NULL then there is no anagram, otherwise if strchr() returns a valid pointer, use it to modify the copy, e.g. set to char value to 0x01, so that you can sum the chars in the modified copy. In this instance, the strings would be anagrams if the sum of all the chars in the modified copy equal the integer length of the comparison string.
This is the sample code of my program, in which i've to add two string type integer (ex: "23568" and "23674"). So, i was trying with single char addition.
char first ='2';
char second ='1';
i was trying like this..
i=((int)first)+((int)second);
printf("%d",i);
and i'm getting output 99, because, it's adding the ASCII value of both. Anyone please suggest me, what should be the approach to add the char type number in C.
Since your example has two single chars being added together, you can be confident knowing two things
The total will never be more than 18.
You can avoid any conversions via library calls entirely. The standard requires that '0' through '9' be sequential (in fact it is the only character sequence that is mandated by the standard).
Therefore;
char a = '2';
char b = '3';
int i = (int)(a-'0') + (int)(b-'0');
will always work. Even in EBCDIC (and if you don't know what that is, consider yourself lucky).
If your intention is to actually add two numbers of multiple digits each currently in string form ("12345", "54321") then strtol() is your best alternative.
i=(first-'0')+(second-'0');
No need for casting char to int.
if you want to add the number reprensations of the characters, I would use "(first - '0') + (second - '0');"
The question seemed interesting, I though it would be easier than it is, adding "String numbers" is a little bit tricky (even more with the ugly approach I used).
This code will add two strings of any length, they doesn't need to be of the same length as the adding begins from the back. Your provide both strings, a buffer of enough length and you ensure the strings only contains digits:
#include <stdio.h>
#include <string.h>
char * add_string_numbers(char * first, char * second, char * dest, int dest_len)
{
char * res = dest + dest_len - 1;
*res = 0;
if ( ! *first && ! *second )
{
puts("Those numbers are less than nothing");
return 0;
}
int first_len = strlen(first);
int second_len = strlen(second);
if ( ((first_len+2) > dest_len) || ((second_len+2) > dest_len) )
{
puts("Possibly not enough space on destination buffer");
return 0;
}
char *first_back = first+first_len;
char *second_back = second+second_len;
char sum;
char carry = 0;
while ( (first_back > first) || (second_back > second) )
{
sum = ((first_back > first) ? *(--first_back) : '0')
+ ((second_back > second) ? *(--second_back) : '0')
+ carry - '0';
carry = sum > '9';
if ( carry )
{
sum -= 10;
}
if ( sum > '9' )
{
sum = '0';
carry = 1;
}
*(--res) = sum;
}
if ( carry )
{
*(--res) = '1';
}
return res;
}
int main(int argc, char** argv)
{
char * a = "555555555555555555555555555555555555555555555555555555555555555";
char * b = "9999999999999666666666666666666666666666666666666666666666666666666666666666";
char r[100] = {0};
char * res = add_string_numbers(a,b,r,sizeof(r));
printf("%s + %s = %s", a, b, res);
return (0);
}
Well... you are already adding char types, as you noted that's 4910 and 5010 which should give you 9910
If you're asking how to add the reperserented value of two characters i.e. '1' + '2' == 3 you can subtract the base '0':
printf("%d",('2'-'0') + ('1'-'0'));
This gives 3 as an int because:
'0' = ASCII 48<sub>10</sub>
'1' = ASCII 49<sub>10</sub>
'2' = ASCII 50<sub>10</sub>
So you're doing:
printf("%d",(50-48) + (49-48));
If you want to do a longer number, you can use atoi(), but you have to use strings at that point:
int * first = "123";
int * second = "100";
printf("%d", atoi(first) + atoi(second));
>> 223
In fact, you don't need to even type cast the chars for doing this with a single char:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
char f1 = '9';
char f2 = '7';
int v = (f1 - '0') - (f2 - '0');
printf("%d\n", v);
return 0;
}
Will print 2
But beware, it won't work for hexadecimal chars
This will add the corresponding characters of any two given number strings using the ASCII codes.
Given two number strings 'a' and 'b', we can compute the sum of a and b using their ASCII values without type casting or trying to convert them to int data type before addition.
Let
char *a = "13784", *b = "94325";
int max_len, carry = 0, i, j; /*( Note: max_len is the length of the longest string)*/
char sum, *result;
Adding corresponding digits in a and b.
sum = a[i] + (b[i] - 48) + carry; /*(Because 0 starts from 48 in ASCII) */
if (sum >= 57)
result[max_len - j] = sum - 10;
carry = 1;
else
result[max_len - j] = sum;
carry = 0;
/* where (0 < i <= max_len and 0 <= j <= max_len) */
NOTE:
The above solution only takes account of single character addition starting from the right and moving leftward.
if you want to scan number by number, simple atoi function will do it
you can use
atoi() function
#include <stdio.h>
#include <stdlib.h>
void main(){
char f[] = {"1"};
char s[] = {"2"};
int i, k;
i = atoi(f);
k = atoi(s);
printf("%d", i + k);
getchar();
}
Hope I answered you question
I have a variable length string where each character represents a hex digit. I could iterate through the characters and use a case statement to convert it to hex but I feel like there has to be a standard library function that will handle this. Is there any such thing?
Example of what I want to do. "17bf59c" -> int intarray[7] = { 1, 7, 0xb, 0xf, 5, 9, 0xc}
No, there's no such function, probably because (and now I'm guessing, I'm not a C standard library architect by a long stretch) it's something that's quite easy to put together from existing functions. Here's one way of doing it decently:
int * string_to_int_array(const char *string, size_t length)
{
int *out = malloc(length * sizeof *out);
if(out != NULL)
{
size_t i;
for(i = 0; i < length; i++)
{
const char here = tolower(string[i]);
out[i] = (here <= '9') ? (here - '\0') : (10 + (here - 'a'));
}
}
return out;
}
Note: the above is untested.
Also note things that maybe aren't obvious, but still subtly important (in my opinion):
Use const for pointer arguments that are treated as "read only" by the function.
Don't repeat the type that out is pointing at, use sizeof *out.
Don't cast the return value of malloc() in C.
Check that malloc() succeeded before using the memory.
Don't hard-code ASCII values, use character constants.
The above still assumes an encoding where 'a'..'f' are contigous, and would likely break on e.g. EBCDIC. You get what you pay for, sometimes. :)
using strtol
void to_int_array (int *dst, const char *hexs)
{
char buf[2] = {0};
char c;
while ((c = *hexs++)) {
buf[0] = c;
*dst++ = strtol(buf,NULL,16);
}
}
Here's another version that allows you to pass in the output array. Most of the time, you don't need to malloc, and that's expensive. A stack variable is typically fine, and you know the output is never going to be bigger than your input. You can still pass in an allocated array, if it's too big, or you need to pass it back up.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* str of length len is parsed to individual ints into output
* length of output needs to be at least len.
* returns number of parsed elements. Maybe shorter if there
* are invalid characters in str.
*/
int string_to_array(const char *str, int *output)
{
int *out = output;
for (; *str; str++) {
if (isxdigit(*str & 0xff)) {
char ch = tolower(*str & 0xff);
*out++ = (ch >= 'a' && ch <= 'z') ? ch - 'a' + 10 : ch - '0';
}
}
return out - output;
}
int main(void)
{
int values[10];
int len = string_to_array("17bzzf59c", values);
int i = 0;
for (i = 0; i < len; i++)
printf("%x ", values[i]);
printf("\n");
return EXIT_SUCCESS;
}
#include <stdio.h>
int main(){
char data[] = "17bf59c";
const int len = sizeof(data)/sizeof(char)-1;
int i,value[sizeof(data)/sizeof(char)-1];
for(i=0;i<len;++i)
sscanf(data+i, "%1x",value + i);
for(i=0;i<len;++i)
printf("0x%x\n", value[i]);
return 0;
}