I have two strings:
char *str1 = "this is a test";
char *str2 = "ts bd a";
I'm trying to write a function that returns a new string with the same chars from the two string without duplicates (also ' ' is duplicate). eg.:
char *retStr = GetSameChars(str1, str2); //returns "ts a";
How can I do that?
What I'm tried:
char *GetSameChars(char str1[], char str2[]) {
int found = -1, i , j = 0, biggest, index = 0;
char *retArr, *star = '*';
int str1Len, str2Len, count = 0;
str1Len = strlen(str1);
str2Len = strlen(str2);
biggest = str1Len > str2Len ? str1Len : str2Len;
retArr = (char *)malloc(sizeof(char) * count);
for (i = 0; i < str1Len; i++) {
for (j = 0; j < str2Len; j++) {
if (str1[i] == str2[j] && found == -1) {
count++;
found = j;
} else
if (str2[j] == str2[found])
str2[j] = star; //Throw an exception
}
found = -1;
}
retArr = (char *)malloc(sizeof(char) * count);
j = 0;
for (i = 0; i < str2Len; i++)
if (str2[i] != '*')
retArr[j++] = str2[i];
for (i = 0; i < str2Len; i++)
printf("%c", retArr[i]);
}
When I tried the line str2[j] = star; I got an exception.
What is my mistake?
My recommendations would be: keep it simple; get to know the C standard library; write less, test more.
Some specific problems with your code: you pass the wrong variable to malloc(); you estimate the answer to fit in the size of the larger of the two strings but it will actually fit into the smaller of the two; you modify an argument string str2[j] = star -- you should be treating the arguments as readonly; you malloc() retArr twice unnecessarily, leaking the first one when you allocate the second; your algorithm simply doesn't work.
Although a lookup table, as others have suggested, would be more efficient, let's use the standard library routine strchr() to solve this problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *getSameChars(const char *string1, const char *string2) {
size_t string1_length = strlen(string1);
size_t string2_length = strlen(string2);
size_t shortest = string1_length < string2_length ? string1_length : string2_length;
char *common_pointer, *common = malloc(shortest + 1);
*(common_pointer = common) = '\0';
for (size_t i = 0; i < string1_length; i++) {
// character found in both input strings, but not yet in common string
if (strchr(string2, string1[i]) != NULL && strchr(common, string1[i]) == NULL) {
*common_pointer++ = string1[i];
*common_pointer = '\0';
}
}
return common;
}
int main() {
char *stringA = "this is a test";
char *stringB = "ts bd a";
char *result = getSameChars(stringA, stringB);
printf("%s\n", result);
free(result);
return(0);
}
Your code complains because you are trying to assign a pointer to a char, to get the value inside a pointer you need to use the * operator like so:
*star;
a good way to check if a letter have already appeared(if you want to use it on all of the ascii table then 128) is to use a lookup table. first you will need to declare an array the length of all letters in the alphabet like so:
char lut[26];
If it is a global variable then it will be set to 0, then all you need to do is go to the index of the char you got and mark it as 1, a simple if will later be able to determine if a letter has already appeard.
example:
lut[toupper(somechar) - 'A'] = 1;
In this example you set the char in the lookup table that is equivalent to the somechar variable as 1, marking it has already appeared.
hope this helps.
Related
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
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int len = 3; // length of word
char * word = "cat"; // word to be sorted
char sortedWord[len];
int i, j, temp;
// store chars from 'word' to an array 'sortedWord[]'
for (i = 0; i < len; i++) {
sortedWord[i] = *word;
word++;
}
// sort the array using bubble sort
for (i = 0; i < len - 1; i++) {
for (j = 0; j < len - i - 1; j++) {
if (sortedWord[j] > sortedWord[j + 1]) {
temp = sortedWord[j];
sortedWord[j] = sortedWord[j + 1];
sortedWord[j + 1] = temp;
}
}
}
printf("%s\n", sortedWord);
}
The focus of this question is the variable 'len'. If I were to define len to be equal to 3, then the output is as expected (i.e. "act"). However, I want to be able to find the length without explicitly defining it.
I have tried to define len as:
int len = strlen (word);
However, the output is not as expected. It would give me results such as actW?, actX?, and so on.
This same behavior occurs when I try to define len as:
int len;
for (len = 0; *word != '\0'; len++) {
word++;
}
Surprisingly, if I were to print the the variable len right after explicitly defining it, it would also behave the same way.
int len = 3;
printf("Length: %d\n", len); // will cause the output to be different
I am sure that I am missing a fundamental concept, but I am not sure on an approach to resolve this problem. Thanks in advance!
Your storeWord is not null terminated causing undefined behavior, add the null terminator and it will no longer behave erratically.
And also, if you increment the word pointer, it will end up pointing to the null terminator of the original string, so don't do that. Instead, use the index to access elements.
char sortedWord[len + 1]; // One more for the '\0'
int i, j, temp;
// store chars from 'word' to an array 'sortedWord[]'
for (i = 0; i < len; i++) {
sortedWord[i] = word[i];
}
storeWord[len] = '\0';
One more thing, when writing pointers to string literals, use const to prevent accidentally modifiying them, since that is undefined behavior too, so
const char *word = "cat";
I have an array of chars that I would like to set to 1 variable. How would I go about doing this. For example I would have the following code:
char list[5] = {'B','O','B','B','Y'};
how would I have it so that I could set it to a variable to have it so that:
char *name = "BOBBY"
pulling the values from the list shown above.
In addition to the other answers, there is a simpler solution for systems conforming to POSIX 1-2008, such as linux and OS/X:
char *name = strndup(list, sizeof(list));
Since the string is not null terminated you cannot assume that functions like strcpy will succeed - you will need to do something in O(n) that copies each character one by one:
char *str = NULL;
int len_orig = sizeof(list);
int i;
str = malloc(len_orig+1);
if(!str)
{
perror("malloc");
exit(EXIT_FAILURE);
}
for(i = 0; i < len_orig; i++)
{
str[i] = list[i];
}
str[len_orig]=0;
// use str...
free(str);
char* temp = malloc(sizeof(char) * 6); // 6 because 5 + 1 for null terminator
for(int i = 0; i < 5; ++i)
temp[i] = list[i];
temp[5] = '\0';
You can do this, I'd not use strcpy for this as your array is not null-terminated.
I'm supposed to copy char orig[] to char reversed[] and reverse it. My function works but doesn't properly reset the string as evidenced by the fact that a blank string returns the prior test results. How can I fix this?
void reverse(char orig[], char reversed[]) {
int lastChar = strlen(orig) - 1;
int lastCopy = lastChar;
int i;
for(i = 0; i < lastChar; i++){
reversed[lastCopy] = orig[i];
reversed[i] = orig[lastCopy];
lastCopy--;
reversed[lastChar+1] = '\0';
}
return ;
}
This is what I get as output:
Test "software" (Pass, returns: erawtfos)
Test the empty string
Assertion failure
Have: <erawtfos>
Expect: <>
Test a long string (Pass)
Test a simple palindrome (Pass)
4 assertions: 3 passed 1 failed
OP problem: When the original string orig has length 0 or 1, the null character is never set in reversed.
Instead create a simple loop pulling 1 char at a time.
// As `orig` elements are not changed, good C style to make it `const`
void reverse(const char orig[], char reversed[]) {
// use `size_t` as `int` may be too narrow
size_t length = strlen(orig);
size_t i;
for(i = 0; i < length; i++) {
reversed[i] = orig[length - i - 1];
}
reversed[i] = '\0';
}
If orig and reversed might overlap, a temporary copy is needed.
void reverse(const char orig[], char reversed[]) {
size_t length = strlen(orig);
char tmp[length+1]; // Add 1 because an array of size 0 is UB
memcpy(tmp, orig, length);
size_t i;
for(i = 0; i < length; i++) {
reversed[i] = tmp[length - i - 1];
}
reversed[i] = '\0';
}
Simplify:
void reverse(char orig[], char reversed[]) {
int len = strlen(orig);
int last = len - 1;
reversed[len] = '\0';
for (int i = 0; i < len; i += 1) {
reversed[last] = orig[i];
last -= 1;
}
return;
}
you can use built in functions like string::rbegin(),string::rend()
in order to copy string reversely.
string copy(orig.rbegin(),orig.rend());
don't forget to include < string.h >
I'm trying to take a string and break it into "word" components and store that in an array of strings.
"Hello my name is Bill." should give back a char** with elements, "Hello", "my", "name", "is", and "Bill."
My code will compile however I keep encountering a runtime error (I don't get warnings anymore and my debugger gdb doesn't work)>
I'm running on minGW on Window 8.
#include <stdio.h>
#include <stdlib.h>
char** words(char* string)
{
int i = 0;
int j = 0;
int k =0;
int count = 0;
char** stringArray = (char**) malloc(sizeof(char)*30*30);
while( string[i] != '\0' )
{
if(string[i] != ' ')
{
j =0;
while(string[i+j+1] != ' ')
{
j++;
}
i = i+j;
for(k=0; k<=j; k++)
{
stringArray[count][k] = string[i+k];
}
count++;
}
i++;
}
return stringArray;
}
int main()
{
char message[20] = "abcd efgh ijkl mno";
char** wordArray = words(message);
printf("%c\n\n", wordArray[0][0]);
int i =0;
while(wordArray[i])
{
printf("%s\n", wordArray[i]);
i++;
}
printf("\nThe problem is not with the words function");
return 0;
}
There are couple of issues that have been mentioned in the comments.
The allocation should look something like:
#include <ctype.h> // for isspace()
#define MAXSTRLEN 30 // using a symbolic constant
char **stringArray;
int i, j, k;
stringArray = malloc(sizeof(char*) * MAXSTRLEN); // don't cast from malloc
for (i = 0; i < 30; ++i) {
stringArray[i] = malloc(sizeof(char) * MAXSTRLEN);
}
// TODO error checking: malloc could return NULL
while copying the substrings would look like:
i = 0;
j = 0;
while( string[i] != '\0') // go through the whole string
{
while (string[i] != '\0' && isspace(string[i])) {
i++; // skip whitespaces
}
k = 0;
while (string[i] != '\0' && !isspace(string[i])) { // copy word until whitepace or end of string
stringArray[j][k++] = string[i++];
}
stringArray[j][k] = '\0'; // EOS !!!
j++;
}
and printing (j is number of words actually read):
for (i = 0; i < j/*30*/; ++i) { // (!) how to print
printf("%s\n", stringArray[i]);
}
And, yes strtok would also do the job.
In words() you're assigning values to stringArray as a two-dimensional array, and in main() you're reading values from it as an array of pointers. Those are not the same thing.
So you need to change it so that you're consistently treating it as a 2D array, or so that you're consistently treating it as an array of pointers (char* to be exact). Either will work... see the comments above for elaboration.
This code is all wrong.
char** stringArray = (char**) malloc(sizeof(char)*30*30);
First of all, sizeof(char) is always one, second, you don't need to cast a void. So:
char **stringArray = malloc(30 * 30);
But that doesn't make any sense because it's an array of char *, so you should allocate in terms of that:
char **stringArray = malloc(sizeof(char *) * 30);
Or even better:
char **stringArray = malloc(sizeof(*stringArray) * 30);
So now you have an array with 30 char *, but each of those is not initialized, so you need to do that:
for (i = 0; i < 30; i++)
stringArray[i] = malloc(sizeof(**stringArray) * 30);
If you don't do that, you can't access stringArray[count][k].
And then you assume the last element in the array is NULL, but you never set it, so you either do stringArray[count] = NULL at the end of words(), or you do calloc() instead of malloc().
I'm not analyzing the code beyond that; it's just all wrong.