print string based on the frequency of character in C - c

I was solving the question of leet code in C
Question:
Given a string s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string.
Return the sorted string. If there are multiple answers, return any of them.
Example 1:
Input: s = "tree"
Output: "eert"
Explanation: 'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
I tried to use the different approach instead taking the array[255] and increasing the array value in specific char ASCII index. But I m getting segmentation fault. I not understand why I m getting segmentation voilation. Only assumption I made here is input str always be in UPPER CASE.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *frequencySort(char *s)
{
int strlenn = strlen(s);
int fq[strlenn];
// init with 1 because at least 1 time char occur in input str.
for (int i = 0; i < strlenn; i++)
{
fq[i] = 1;
}
// count freq of string and replace dublicate char with *
// ex: ABCDA => ABCD*
for (int i = 0; i < strlenn - 1; i++)
{
if (s[i] == '*')
{
continue;
}
for (int j = (i + 1); j < strlenn; j++)
{
if (s[i] == s[j])
{
fq[i]++;
s[j] = (char)'*'; // segmentation violation error shows here
fq[j] = 0;
}
}
}
// sort freqency by in decending order and str char
// ex: ABCDDDAA = freq[3, 3, 1, 1] = soredt str = [ A, D, B, C ]
for (int i = 0; i < strlenn - 1; i++)
{
for (int j = i + 1; j < strlenn; j++)
{
if (fq[i] < fq[j])
{
// swap
int temp = fq[i];
fq[i] = fq[j];
fq[j] = temp;
// swap string char
char temp1 = s[i];
s[i] = s[j]; // segmentation violation error shows here
s[j] = temp1;
}
}
}
char *result = (char *)calloc(strlenn + 1, sizeof(char));
int l = 0;
for (int i = 0; fq[i] != 0 && i < strlenn; i++)
{
int k = fq[i];
while (k > 0)
{
printf("%c", s[i]);
result[l++] = s[i];
k--;
}
}
result[l] = '\0';
return result;
}
int main()
{
char *s = "ABCDDDAA";
frequencySort(s);
return 0;
}
Thanks!

In frequencySort, you are modifying s (e.g.):
s[j] = (char)'*'; // segmentation violation error shows here
In main, the s argument comes from:
char *s = "ABCDDDAA";
frequencySort(s);
Here s is function scoped and goes on the stack.
But, because this is a pointer to a string literal, the actual string data goes into the .rodata section. This is mapped as read only. So, when we try to change it, we get a protection exception.
To fix this, define a string array:
char s[] = "ABCDDDAA";
frequencySort(s);
Now the literal data is [still] in the .rodata section. But, when main starts up, it is copied into the s array which is on the stack [which is writable].

Related

Why C dosen't split correctly arrays?

I have an array of 64 characters, which I need to divide into two parts, the left part of 32 characters and the right part, also 32 characters.
char *IP_M; // 64 characters array
char L[32]; // left part
char R[32]; // right part
The IP_M array is filled in as follow:
char *start_inital_permutation(const char *input) {
char *output = malloc(64 * sizeof(char));
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
output[i * 8 + j] = input[IP[i][j] - 1];
}
}
return output;
}
...
IP_M = start_inital_permutation(M);
where M is also a 64 characters string. With the following method I tried to fill the other two array (L, R) by spliting the IP_M.
void fill_LR() {
for (int i = 0; i < 32; i++) {
L[i] = IP_M[i];
R[i] = IP_M[i + 32];
}
}
but when I run the following instructions:
printf("IP_M: %s\n", IP_M);
printf("L: %s\n", L);
printf("R: %s\n", R);
the output is:
IP_M: 1100110000000000110011001111111111110000101010101111000010101010
L: 1100110000000000110011001111111111110000101010101111000010101010
R: 11110000101010101111000010101010
I can't get out of this situation, can someone help me please?
*EDIT: also tried the memcpy() method but it still not work!
Here is the Project if someone want to see it:
https://github.com/ionutbogdandonici/DES_C.git
Strings in C are \0 terminated. So the print function will print the string until it reaches the \0 character.
Assign space for null:
char L[33]; // left part
char R[33]; // right part
Add null terminator:
void fill_LR() {
for (int i = 0; i < 32; i++) {
L[i] = IP_M[i];
R[i] = IP_M[i + 32];
}
L[32] = 0;
R[32] = 0;
}
output[i * 8 + j] = input[IP[i][j] - 1]; is gibberish.
Strings in C are null terminated but you never allocate space for a null terminator anywhere, nor do you null terminate your strings.
Don't use global variables.
I was able to salvage your program like this:
#include <stdio.h>
#include <stdlib.h>
char *start_inital_permutation(const char *input) {
size_t count=0;
char *output = malloc(64 * sizeof(char) + 1);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
output[i * 8 + j] = input[count++];
}
}
output[64] = '\0';
return output;
}
int main()
{
const char input[] = "1100110000000000110011001111111111110000101010101111000010101010";
char *IP_M = start_inital_permutation(input);
char L[32+1]; // left part
char R[32+1]; // right part
for (int i = 0; i < 32; i++) {
L[i] = IP_M[i];
R[i] = IP_M[i + 32];
}
L[32] = '\0';
R[32] = '\0';
printf("IP_M: %s\n", IP_M);
printf("L: %s\n", L);
printf("R: %s\n", R);
}
However, there's no apparent reason why you need to do the middle step with the 64 characters array. You could as well put that one in a union and save the copy (although then the individual left/right strings won't be null terminated). Example:
#include <stdio.h>
#include <stdlib.h>
typedef union
{
char data [64+1];
struct
{
char left[32];
char right[32];
char zero;
};
} ip_t;
ip_t *start_inital_permutation(const char *input) {
size_t count=0;
ip_t* obj = malloc(sizeof(ip_t));
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
obj->data[i * 8 + j] = input[count++];
}
}
obj->data[64] = '\0';
return obj;
}
int main()
{
const char input[] = "1100110000000000110011001111111111110000101010101111000010101010";
ip_t *IP_M = start_inital_permutation(input);
printf("IP_M: %s\n", IP_M->data);
printf("L: %.32s\n", IP_M->left);
printf("R: %.32s\n", IP_M->right);
}
Using printf with "%s" assumes the value is a zero terminated string (AKA NULL terminated string).
I.e. a pointer to a sequence of chars, ending with a \0 char.
In your case when printf attempts to print L it prints char, and after the 32 chars that belong to L it continues. It happened to be that R is following L in memory, and so the content of R is also dumped. If the next byte in memory following R was not a 0, you would see even more characters printed. This behavior is dependent on the [possibly atrbitarary] content of your memory.
How to handle the issue (2 ways):
1. You can either increase the size of L and R to 33, and assign the last char to \0:
char L[33]; // left part
char R[33]; // right part
/* ... */
L[32] = '\0';
R[32] = '\0';
2. Or specify to printf the length of the strings (32) like this:
/*----------vvv-------*/
printf("L: %.32s\n", L);
printf("R: %.32s\n", R);
In the later case keep in mind that L and R are not "regular" C strings, which are expected to be zero terminated (at least as far as it concerns common functions like strlen, strcmp etc.).

My system is showing wrong output for correct code and the same code is giving correct output in other device.How to rectify this issue?

I have written the code in c language(for n factorial).
The code is-->
#include <stdio.h>
#include <string.h>
int main()
{
int n;
scanf("%d", &n);
char str[200];
str[0] = '1';
int k;
int t = 0;
int carry = 0;
for (int i = 1; i <= n; i++)
{
carry = 0;
for (int j = 0;; j++)
{
int arr = str[j] - 48;
k = arr * i + carry;
arr = k % 10;
str[j] = arr + 48;
carry = k / 10;
if (carry == 0 && str[j + 1] == '\0')
{
break;
}
if (carry != 0 && str[j + 1] == '\0')
{
for (int r = j;; r++)
{
str[r + 1] = (carry % 10) + 48;
carry = carry / 10;
if (carry == 0)
{
str[r + 2] = '\0';
t = 1;
break;
}
}
break;
}
}
}
int len = strlen(str);
// // printf("%d\n",len);
char prr[200];
for (int i = 0; i < len; i++)
{
int b = len - i - 1;
printf("%c", str[b]);
}
// printf(" %s\n", str);
return 0;
}
In other systems(including online c compilers) it is showing correct answer
Input=7
Output=5040
In my system(laptop):
Input=7
Output=+,*)'040
My laptop is hp envy 13-ab070TU
os:Windows 10 Home
system type:64-bit operating system, x64-based processor
I have also tried my code on virtual machine in my laptop on ubuntu and kali but the result is same that it is showing wrong output.
What is the reason for this and how I can rectify this issue?
You're filling digits in to your str array, but str is not necessarily a proper, null-terminated string.
At the end, you call strlen(str) to discover how many digits you computed in your result. But since str is not necessarily a null-terminated string, strlen doesn't necessarily get the right answer.
str is a local (stack allocated) variable, and you don't give it an initializer, so it starts out containing unpredictable garbage.
If str happens to start out containing zeroes (which it might), your program will happen to work. But if it contains one or more nonzero bytes, strlen might compute too long a length, so your digit-printing loop at the end might print some extra characters, as you saw on your laptop.
There are two or three ways to fix this.
Call memset(str, '\0', sizeof(str)); to fill the array with 0.
Initialize the array: char str[200] = "";. (It turns out that will fill the whole array with 0.)
Keep track of the number of digits some other way. I suspect it's the maximum value ever taken on by k or r, or something like that.

How to store a substring given a delimiter in C

Let's say I have a series of data that's in this form:
"SomethingIDontCareAbout : SomethingICareAbout"
where the part after the ":" can vary in length of course.
The goal here is only storing the "SomethingICareAbout" substring efficiently. I made this function but the problem is that I'm storing both substrings,so it seems like a waste of memory. Any help to reduce to the time/space complexity?
char** ExtractKey(char* S)
{
int n = strlen(S);
int count = 0, i = 0, j = 0;
for(i = 0; i < n; i++)
{
if(S[i] == ':')
break;
count++;
}
char** T = (char**)malloc(2 * sizeof(char*));
T[0] = (char*)malloc((count + 1) * sizeof(char));
T[1] = (char*)malloc((n - count) * sizeof(char));
for(i = 0; i < count; i++) // inefficient ? cus we won't need T[0] [j]
{
T[0][j] = S[i];
j++;
}
T[0][j+1] = '\0';
j = 0;
for(i = count + 1; i < n; i++)
{
T[1][j] = S[i];
j++;
}
T[1][j+1] = '\0';
return T;
}
There is no reason to invent a search for a character in a string, or a copy of a string.
If the input data will live long enough for you to use the "value" part, just return a pointer to the value:
char* ExtractKey(char* S)
{
return strchr(S, ':');
}
If it doesn't, or if you for some reason need a separate copy:
char* ExtractKey(char* S)
{
return strdup(strchr(S, ':'));
}
Honestly, this could be done efficiently if strtok() was used to split those strings. I have designed the following code that parses each string of a 2-D array with a common delimiter that is : here.
Now, let's take a look into the code (notice the comments):
#include <stdio.h>
#include <string.h>
#define MAX_LEN 128
int main(void) {
// The 2-D string
char str[][MAX_LEN] = {"SomethingElse : SomethingToCareAbout",
"Something2 : SomethingToCare2",
"Unnecessary : Necessary"};
int size = sizeof(str) / sizeof(str[0]);
// Applying Variable-Length Array (valid in C)
char store_cared_ones[size][MAX_LEN];
for (int i = 0; i < size; i++) {
// Declaring a temporary pointer variable to obtain the required
// substring from each string
char *sub_str = NULL;
sub_str = strtok(str[i], ": ");
sub_str = strtok(NULL, ": ");
// Copying the 'sub_str' into each array element of 'store_cared_ones'
strcpy(store_cared_ones[i], sub_str);
}
// Displaying each of 'store_cared_ones'
for (int i = 0; i < size; i++)
fprintf(stdout, "%s\n", store_cared_ones[i]);
return 0;
}
Finally, let's see what that code does:
rohanbari#genesis:~/stack$ ./a.out
SomethingToCareAbout
SomethingToCare2
Necessary

Hash function C

I am having trouble implementing my hash function for my hash table.
I want to hash my words such that A = 1, B = 2, C = 3, and so on. The position of the letter in the word is irrelevant, since we will consider permutations of the word. Moreover, the case of the letter will be irrelevant in this problem as well, so the value of a = the value of A = 1.
And for strings, abc = 1 + 2 + 3 = 6, bc = 2 + 3 = 5, etc.
And for cases where ab = 3 and aaa = 3, I have already had a way to handle that situation. Right now I just want to get the hash value.
The problem I am having right now is that aaa is giving me 1, and ab is giving me 2.
Below is my code:
int hash(char *word)
{
int h = 1;
int i, j;
char *A;
char *a;
// an array of 26 slots for 26 uppercase letters in the alphabet
A = (char *)malloc(26 * sizeof(char));
// an array of 26 slots for 26 lowercase letters in the alphabet
a = (char *)malloc(26 * sizeof(char));
for (i = 0; i < 26; i++) {
A[i] = (char)(i + 65); // fill the array from A to Z
a[i] = (char)(i + 97); // fill the array from a to z
}
for (i = 0; i < strlen(word); i++) {
//printf("HIT\n");
for (j = 0; j < 26; j++) {
// upper and lower case have the same hash value
if (word[i] == A[j] || word[i] == a[j]) {
h = h + j; // get the hash value of the word
//printf("HIT 2\n");
break;
}
}
}
printf("H: %d\n", h);
return h;
}
I think that changing
int h = 1;
to
int h = 0;
and
h = h + j;
to
h = h + j + 1;
will fix the issue.
The one other problem is that you forgot to free the malloced memory. Also, there is no need to cast the result of malloc(and family) in C.
This
for (i = 0; i < strlen(word); i++) {
will call strlen in every iteration of the loop. This will reduce the performance of your program. Use
int len = strlen(word);
for (i = 0; i < len; i++) {
instead, which is much faster as strlen isn't called in every iteration. Lastly, sizeof(char) is 1. So you can omit it.
change h=h+j to h=h+j+1
and h=1 to h=0.
Also you should free the allocated memory so include these lines just before return:
free(A);
free(a);
However I don't understand why so complicated code was written for such a simple task.
A much simpler code can be written:
int hash(char *word)
{
int sum=0;
while(*word != '\0')
{
if(*word >='A' && *word < 'A'+26)
sum=sum+(*word -'A' + 1);
else if(*word >='a' && *word < 'a'+26)
sum=sum+(*word -'a' + 1);
else
return -1;
word++;
}
return sum;
}
Multiple issues:
You still aren't freeing the arrays you allocated
Initial value of 1 for h makes no sense
You add the index to the hash. 'A' and 'a' are at index 0, so you're adding 0 in that case (so no matter how many 'a' s you give your code will return 1)
Why a dynamic array? You know the size, it isn't going to change. You could use
char A[26];
char a[26]; // you can also add initialisation, e.g. = {'a', 'b', ...
Why an array in the first place?
So, here is the quick fix, staying close to your code.
Taking all of the above into account, you could simplify to:
int hash(char const * string) {
int h = 0;
for (; *string; ++string) {
int index = tolower(*string) - 'a' + 1;
if ((index > 0) && (index < 27)) {
h += index;
}
}
return h;
}
Live
When only hashing words with non special characters, you need to handle ignored words in the caller somehow.
char hash(char const * string, int * h) {
*h = 0;
for (; *string; ++string) {
int index = tolower(*string) - 'a' + 1;
if ((index > 0) && (index < 27)) {
*h += index;
} else {
return 0;
}
}
return 1;
}
That way you can use the return value to test if the word should be ignored.

How do I allocate memory to my char pointer?

My assignment is to allow the user to enter any input and print the occurrences of letters and words, we also have to print out how many one letter, two, three, etc.. letter words are in the string. I have gotten the letter part of my code to work and have revised my word function several times, but still can't get the word finding function to even begin to work. The compiler says the char pointer word is undeclared when it clearly is. Do I have to allocate memory to it and the array of characters?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void findLetters(char *ptr);
void findWords(char *point);
int main()
{
char textStream[100]; //up to 98 characters and '\n\ and '\0'
printf("enter some text\n");
if (fgets(textStream, sizeof (textStream), stdin)) //input up to 99 characters
{
findLetters(textStream);
findWords(textStream);
}
else
{
printf("fgets failed\n");
}
return 0;
}
void findLetters(char *ptr) //find occurences of all letters
{
int upLetters[26];
int loLetters[26];
int i;
int index;
for (i = 0; i < 26; i++) // set array to all zero
{
upLetters[i] = 0;
loLetters[i] = 0;
}
i = 0;
while (ptr[i] != '\0') // loop until prt[i] is '\0'
{
if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
{
index = ptr[i] - 'A';// subtract 'A' to get index 0-25
upLetters[index]++;//add one
}
if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
{
index = ptr[i] - 'a';//subtract 'a' to get index 0-25
loLetters[index]++;//add one
}
i++;//next character in ptr
}
printf("Number of Occurrences of Uppercase letters\n\n");
for (i = 0; i < 26; i++)//loop through 0 to 25
{
if (upLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
// add 'A' to go from an index back to a character
}
}
printf("\n");
printf("Number of Occurrences of Lowercase letters\n\n");
for (i = 0; i < 26; i++)
{
if (loLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
// add 'a' to go back from an index to a character
}
}
printf("\n");
}
void findWords(char *point)
{
int i = 0;
int k = 0;
int count = 0;
int j = 0;
int space = 0;
int c = 0;
char *word[50];
char word1[50][100];
char* delim = "{ } . , ( ) ";
for (i = 0; i< sizeof(point); i++) //counts # of spaces between words
{
if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
{
space++;
}
}
char *words = strtok(point, delim);
for(;k <= space; k++)
{
word[k] = malloc((words+1) * sizeof(*words));
}
while (words != NULL)
{
printf("%s\n",words);
strcpy(words, word[j++]);
words = strtok(NULL, delim);
}
free(words);
}
This is because you are trying to multiply the pointer position+1 by the size of pointer. Change line 100 to:
word[k] = malloc(strlen(words)+1);
This will solve your compilation problem, but you still have other problems.
You've got a couple of problems in function findWords:
Here,
for (i = 0; i< sizeof(point); i++)
sizeof(point) is the same as sizeof(char*) as point in a char* in the function fincdWords. This is not what you want. Use
for (i = 0; i < strlen(point); i++)
instead. But this might be slow as strlen will be called in every iteration. So I suggest
int len = strlen(point);
for (i = 0; i < len; i++)
The same problem lies here too:
word[k] = malloc((words+1) * sizeof(*words));
It doesn't makes sense what you are trying with (words+1). I think you want
word[k] = malloc( strlen(words) + 1 ); //+1 for the NUL-terminator
You got the arguments all mixed up:
strcpy(words, word[j++]);
You actually wanted
strcpy(word[j++], words);
which copies the contents of words to word[j++].
Here:
free(words);
words was never allocated memory. Since you free a pointer that has not been returned by malloc/calloc/realloc, the code exhibits Undefined Behavior. So, remove that.
You allocated memory for each element of word. So free it using
for(k = 0; k <= space; k++)
{
free(word[k]);
}
Your calculation of the pointer position+1 is wrong. If you want the compilation problem will go away change line 100 to:
word[k] = malloc( 1 + strlen(words));

Resources