Removing Duplicates in an array in C - c

The question is a little complex. The problem here is to get rid of duplicates and save the unique elements of array into another array with their original sequence.
For example :
If the input is entered b a c a d t
The result should be : b a c d t in the exact state that the input entered.
So, for sorting the array then checking couldn't work since I lost the original sequence. I was advised to use array of indices but I don't know how to do. So what is your advise to do that?
For those who are willing to answer the question I wanted to add some specific information.
char** finduni(char *words[100],int limit)
{
//
//Methods here
//
}
is the my function. The array whose duplicates should be removed and stored in a different array is words[100]. So, the process will be done on this. I firstly thought about getting all the elements of words into another array and sort that array but that doesn't work after some tests. Just a reminder for solvers :).

Well, here is a version for char types. Note it doesn't scale.
#include "stdio.h"
#include "string.h"
void removeDuplicates(unsigned char *string)
{
unsigned char allCharacters [256] = { 0 };
int lookAt;
int writeTo = 0;
for(lookAt = 0; lookAt < strlen(string); lookAt++)
{
if(allCharacters[ string[lookAt] ] == 0)
{
allCharacters[ string[lookAt] ] = 1; // mark it seen
string[writeTo++] = string[lookAt]; // copy it
}
}
string[writeTo] = '\0';
}
int main()
{
char word[] = "abbbcdefbbbghasdddaiouasdf";
removeDuplicates(word);
printf("Word is now [%s]\n", word);
return 0;
}
The following is the output:
Word is now [abcdefghsiou]
Is that something like what you want? You can modify the method if there are spaces between the letters, but if you use int, float, double or char * as the types, this method won't scale at all.
EDIT
I posted and then saw your clarification, where it's an array of char *. I'll update the method.
I hope this isn't too much code. I adapted this QuickSort algorithm and basically added index memory to it. The algorithm is O(n log n), as the 3 steps below are additive and that is the worst case complexity of 2 of them.
Sort the array of strings, but every swap should be reflected in the index array as well. After this stage, the i'th element of originalIndices holds the original index of the i'th element of the sorted array.
Remove duplicate elements in the sorted array by setting them to NULL, and setting the index value to elements, which is the highest any can be.
Sort the array of original indices, and make sure every swap is reflected in the array of strings. This gives us back the original array of strings, except the duplicates are at the end and they are all NULL.
For good measure, I return the new count of elements.
Code:
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
void sortArrayAndSetCriteria(char **arr, int elements, int *originalIndices)
{
#define MAX_LEVELS 1000
char *piv;
int beg[MAX_LEVELS], end[MAX_LEVELS], i=0, L, R;
int idx, cidx;
for(idx = 0; idx < elements; idx++)
originalIndices[idx] = idx;
beg[0] = 0;
end[0] = elements;
while (i>=0)
{
L = beg[i];
R = end[i] - 1;
if (L<R)
{
piv = arr[L];
cidx = originalIndices[L];
if (i==MAX_LEVELS-1)
return;
while (L < R)
{
while (strcmp(arr[R], piv) >= 0 && L < R) R--;
if (L < R)
{
arr[L] = arr[R];
originalIndices[L++] = originalIndices[R];
}
while (strcmp(arr[L], piv) <= 0 && L < R) L++;
if (L < R)
{
arr[R] = arr[L];
originalIndices[R--] = originalIndices[L];
}
}
arr[L] = piv;
originalIndices[L] = cidx;
beg[i + 1] = L + 1;
end[i + 1] = end[i];
end[i++] = L;
}
else
{
i--;
}
}
}
int removeDuplicatesFromBoth(char **arr, int elements, int *originalIndices)
{
// now remove duplicates
int i = 1, newLimit = 1;
char *curr = arr[0];
while (i < elements)
{
if(strcmp(curr, arr[i]) == 0)
{
arr[i] = NULL; // free this if it was malloc'd
originalIndices[i] = elements; // place it at the end
}
else
{
curr = arr[i];
newLimit++;
}
i++;
}
return newLimit;
}
void sortArrayBasedOnCriteria(char **arr, int elements, int *originalIndices)
{
#define MAX_LEVELS 1000
int piv;
int beg[MAX_LEVELS], end[MAX_LEVELS], i=0, L, R;
int idx;
char *cidx;
beg[0] = 0;
end[0] = elements;
while (i>=0)
{
L = beg[i];
R = end[i] - 1;
if (L<R)
{
piv = originalIndices[L];
cidx = arr[L];
if (i==MAX_LEVELS-1)
return;
while (L < R)
{
while (originalIndices[R] >= piv && L < R) R--;
if (L < R)
{
arr[L] = arr[R];
originalIndices[L++] = originalIndices[R];
}
while (originalIndices[L] <= piv && L < R) L++;
if (L < R)
{
arr[R] = arr[L];
originalIndices[R--] = originalIndices[L];
}
}
arr[L] = cidx;
originalIndices[L] = piv;
beg[i + 1] = L + 1;
end[i + 1] = end[i];
end[i++] = L;
}
else
{
i--;
}
}
}
int removeDuplicateStrings(char *words[], int limit)
{
int *indices = (int *)malloc(limit * sizeof(int));
int newLimit;
sortArrayAndSetCriteria(words, limit, indices);
newLimit = removeDuplicatesFromBoth(words, limit, indices);
sortArrayBasedOnCriteria(words, limit, indices);
free(indices);
return newLimit;
}
int main()
{
char *words[] = { "abc", "def", "bad", "hello", "captain", "def", "abc", "goodbye" };
int newLimit = removeDuplicateStrings(words, 8);
int i = 0;
for(i = 0; i < newLimit; i++) printf(" Word # %d = %s\n", i, words[i]);
return 0;
}

Traverse through the items in the array - O(n) operation
For each item, add it to another sorted-array
Before adding it to the sorted array, check if the entry already exists - O(log n) operation
Finally, O(n log n) operation

i think that in C you can create a second array. then you copy the element from the original array only if this element is not already in the send array.
this also preserve the order of the element.
if you read the element one by one you can discard the element before insert in the original array, this could speedup the process.

As Thomas suggested in a comment, if each element of the array is guaranteed to be from a limited set of values (such as a char) you can achieve this in O(n) time.
Keep an array of 256 bool (or int if your compiler doesn't support bool) or however many different discrete values could possibly be in the array. Initialize all the values to false.
Scan the input array one-by-one.
For each element, if the corresponding value in the bool array is false, add it to the output array and set the bool array value to true. Otherwise, do nothing.

You know how to do it for char type, right?
You can do same thing with strings, but instead of using array of bools (which is technically an implementation of "set" object), you'll have to simulate the "set"(or array of bools) with a linear array of strings you already encountered. I.e. you have an array of strings you already saw, for each new string you check if it is in array of "seen" strings, if it is, then you ignore it (not unique), if it is not in array, you add it to both array of seen strings and output. If you have a small number of different strings (below 1000), you could ignore performance optimizations, and simply compare each new string with everything you already saw before.
With large number of strings (few thousands), however, you'll need to optimize things a bit:
1) Every time you add a new string to an array of strings you already saw, sort the array with insertion sort algorithm. Don't use quickSort, because insertion sort tends to be faster when data is almost sorted.
2) When checking if string is in array, use binary search.
If number of different strings is reasonable (i.e. you don't have billions of unique strings), this approach should be fast enough.

Related

How can I correctly allocate memory for this MergeSort implementation in C (with the DS I am using)?

My goal here is to perform MergeSort on a dynamic array-like data structure I called a dictionary used to store strings and their relative weights. Sorry if the implementation is dumb, I'm a student and still learning.
Anyway, based on the segfaults I'm getting, I'm incorrectly allocating memory for my structs of type item to be copied over into the temporary lists I'm making. Not sure how to fix this. Code for mergesort and data structure setup is below, any help is appreciated.
/////// DICTIONARY METHODS ////////
typedef struct {
char *item;
int weight;
} item;
typedef struct {
item **wordlist;
//track size of dictionary
int size;
} dict;
//dict constructor
dict* Dict(int count){
//allocate space for dictionary
dict* D = malloc(sizeof(dict));
//allocate space for words
D->wordlist = malloc(sizeof(item*) * count);
//initial size
D->size = 0;
return D;
}
//word constructor
item* Item(char str[]){
//allocate memory for struct
item* W = malloc(sizeof(item));
//allocate memory for string
W->item = malloc(sizeof(char) * strlen(str));
W->weight = 0;
return W;
}
void merge(dict* D, int start, int middle, int stop){
//create ints to track lengths of left and right of array
int leftlen = middle - start + 1;
int rightlen = stop - middle;
//create new temporary dicts to store the two sides of the array
dict* L = Dict(leftlen);
dict* R = Dict(rightlen);
int i, j, k;
//copy elements start through middle into left dict- this gives a segfault
for (int i = 0; i < leftlen; i++){
L->wordlist[i] = malloc(sizeof(item*));
L->wordlist[i] = D->wordlist[start + i];
}
//copy elements middle through end into right dict- this gives a segfault
for (int j = 0; j < rightlen; j++){
R->wordlist[j] = malloc(sizeof(item*));
R->wordlist[j]= D->wordlist[middle + 1 + k];
}
i = 0;
j = 0;
k = leftlen;
while ((i < leftlen) && (j < rightlen)){
if (strcmp(L->wordlist[i]->item, R->wordlist[j]->item) <= 0) {
D->wordlist[k] = L->wordlist[i];
i++;
k++;
}
else{
D->wordlist[k] = R->wordlist[j];
j++;
k++;
}
}
while (i < leftlen){
D->wordlist[k] = L->wordlist[i];
i++;
k++;
}
while (j < rightlen){
D->wordlist[k] = L->wordlist[j];
j++;
k++;
}
}
void mergeSort(dict* D, int start, int stop){
if (start < stop) {
int middle = start + (stop - start) / 2;
mergeSort(D, start, middle);
mergeSort(D, middle + 1, stop);
merge(D, start, middle, stop);
}
I put print statements everywhere and narrowed it down to the mallocs in the section where I copy the dictionary to be sorted into 2 separate dictionaries. Also tried writing that malloc as malloc(sizeof(D->wordlist[start + i])). Is there something else I need to do to be able to copy the item struct into the wordlist of the new struct?
Again, I'm new to this, so cut me some slack :)
There are numerous errors in the code:
In merge() when copying elements to the R list, the wrong (and uninitialized) index variable k is being used instead of j. R->wordlist[j]= D->wordlist[middle + 1 + k]; should be R->wordlist[j]= D->wordlist[middle + 1 + j];.
In merge() before merging the L and R lists back to D, the index variable k for the D list is being initialized to the wrong value. k = leftLen; should be k = start;.
In merge() in the loop that should copy the remaining elements of the "right" list to D, the elements are being copied from the "left" list instead of the "right" list. D->wordlist[k] = L->wordlist[j]; should be D->wordlist[k] = R->wordlist[j];.
In Item(), the malloc() call is not reserving space for the null terminator at the end of the string. W->item = malloc(sizeof(char) * strlen(str)); should be W->item = malloc(sizeof(char) * (strlen(str) + 1)); (and since sizeof(char) is 1 by definition it can be simplified to W->item = malloc(strlen(str) + 1);).
Item() is not copying the string to the allocated memory. Add strcpy(W->item, str);.
There are memory leaks in merge():
L->wordlist[i] = malloc(sizeof(item*)); is not required and can be removed since L->wordlist[i] is changed on the very next line: L->wordlist[i] = D->wordlist[start + i];.
Similarly, R->wordlist[j] = malloc(sizeof(item*)); is not required and can be removed since R->wordlist[j] is changed on the very next line.
L and R memory is created but never destroyed. Add these lines to the end of merge() to free them:
free(L->wordlist);
free(L);
free(R->wordlist);
free(R);
None of the malloc() calls are checked for success.
Allocate it all at once, before the merge sort even starts.
#include <stdlib.h>
#include <string.h>
// Weighted Word --------------------------------------------------------------
//
typedef struct {
char *word;
int weight;
} weighted_word;
// Create a weighted word
//
weighted_word* CreateWeightedWord(const char *str, int weight){
weighted_word* W = malloc(sizeof(weighted_word));
if (W){
W->word = malloc(strlen(str) + 1); // string length + nul terminator
if (W->word)
strcpy( W->word, str);
W->weight = weight;
}
return W;
}
// Free a weighted word
//
weighted_word *FreeWeightedWord(weighted_word *W){
if (W){
if (W->word)
free(W->word);
free(W);
}
return NULL;
}
// Dictionary (of Weighted Words) ---------------------------------------------
//
typedef struct {
weighted_word **wordlist; // this is a pointer to an array of (weighted_word *)s
int size; // current number of elements in use
int capacity; // maximum number of elements available to use
} dict;
// Create a dictionary with a fixed capacity
//
dict* CreateDict(int capacity){
dict* D = malloc(sizeof(dict));
if (D){
D->wordlist = malloc(sizeof(weighted_word*) * capacity);
D->size = 0;
D->capacity = capacity;
}
return D;
}
// Free a dictionary (and all weighted words)
//
dict *FreeDict(dict *D){
if (D){
for (int n = 0; n < D->size; n++)
FreeWeightedWord(D->wordlist[n]);
free(D->wordlist);
free(D);
}
return NULL;
}
// Add a new weighted word to the end of our dictionary
//
void DictAddWord(dict *D, const char *str, int weight){
if (!D) return;
if (D->size == D->capacity) return;
D->wordlist[D->size] = CreateWeightedWord(str, weight);
if (D->wordlist[D->size])
D->size += 1;
}
// Merge Sort the Dictionary --------------------------------------------------
// Merge two partitions of sorted words
// words • the partitioned weighted word list
// start • beginning of left partition
// middle • end of left partition, beginning of right partition
// stop • end of right partition
// buffer • temporary work buffer, at least as big as (middle-start)
//
void MergeWeightedWords(weighted_word **words, int start, int middle, int stop, weighted_word **buffer){
int Lstart = start; int Rstart = middle; // Left partition
int Lstop = middle; int Rstop = stop; // Right partition
int Bindex = 0; // temporary work buffer output index
// while (left partition has elements) AND (right partition has elements)
while ((Lstart < Lstop) && (Rstart < Rstop)){
if (strcmp( words[Rstart]->word, words[Lstart]->word ) < 0)
buffer[Bindex++] = words[Rstart++];
else
buffer[Bindex++] = words[Lstart++];
}
// if (left partition has any remaining elements)
while (Lstart < Lstop)
buffer[Bindex++] = words[Lstart++];
// We don't actually need this. Think about it. Why not?
// // if (right partition has any remaining elements)
// while (Rstart < Rstop)
// buffer[Bindex++] = words[Rstart++];
// Copy merged data from temporary buffer back into source word list
for (int n = 0; n < Bindex; n++)
words[start++] = buffer[n];
}
// Merge Sort an array of weighted words
// words • the array of (weighted_word*)s to sort
// start • index of first element to sort
// stop • index ONE PAST the last element to sort
// buffer • the temporary merge buffer, at least as big as (stop-start+1)/2
//
void MergeSortWeightedWords(weighted_word **words, int start, int stop, weighted_word **buffer){
if (start < stop-1){ // -1 because a singleton array is by definition sorted
int middle = start + (stop - start) / 2;
MergeSortWeightedWords(words, start, middle, buffer);
MergeSortWeightedWords(words, middle, stop, buffer);
MergeWeightedWords(words, start, middle, stop, buffer);
}
}
// Merge Sort a Dictionary
//
void MergeSortDict(dict *D){
if (D){
// We only need to allocate a single temporary work buffer, just once, right here.
dict * Temp = CreateDict(D->size);
if (Temp){
MergeSortWeightedWords(D->wordlist, 0, D->size, Temp->wordlist);
}
FreeDict(Temp);
}
}
// Main program ---------------------------------------------------------------
#include <stdio.h>
int main(int argc, char **argv){
// Command-line arguments --> dictionary
dict *a_dict = CreateDict(argc-1);
for (int n = 1; n < argc; n++)
DictAddWord(a_dict, argv[n], 0);
// Sort the dictionary
MergeSortDict(a_dict);
// Print the weighted words
for (int n = 0; n < a_dict->size; n++)
printf( "%d %s\n", a_dict->wordlist[n]->weight, a_dict->wordlist[n]->word );
// Clean up
FreeDict(a_dict);
}
Notes for you:
Be consistent. You were inconsistent with capitalization and * placement and, oddly, vertical spacing. (You are waaay better than most beginners, though.) I personally hate the Egyptian brace style, but to each his own.
I personally think there are far too many levels of malloc()s in this code too, but I will leave it at this one comment. It works as is.
Strings must be nul-terminated — that is, each string takes strlen() characters plus one for a '\0' character. There is a convenient library function that can copy a string for you too, called strdup(), which AFAIK exists on every system.
Always check that malloc() and friends succeed.
Don’t forget to free everything you allocate. Functions help.
“Item” was a terribly non-descript name, and it overlapped with the meaning of two different things in your code. I renamed them to separate things.
Your dictionary object should be expected to keep track of how many elements it can support. The above code simply refuses to add words after the capacity is filled, but you could easily make it realloc() a larger capacity if the need arises. The point is to prevent invalid array accesses by adding too many elements to a fixed-size array.
Printing the array could probably go in a function.
Notice how I set start as inclusive and stop as exclusive. This is a very C (and C++) way of looking at things, and it is a good one. It will help you with all kinds of algorithms.
Notice also how I split the Merge Sort up into two functions: one that takes a dictionary as argument, and a lower-level one that takes an array of the weighted words as argument that does all the work.
The higher-level merge sort a dictionary allocates all the temporary buffer the merge algorithm needs, just once.
The lower-level merge sort an array of (weighted_word*)s expects that temporary buffer to exist and doesn’t care (or know anything) about the dictionary object.
The merge algorithm likewise doesn't know much. It is simply given all the information it needs.
Right now the merge condition simply compares the weighted-word’s string value. But it doesn’t have to be so simple. For example, you could sort equal elements by weight. Create a function:
int CompareWeightedWords(const weighted_word *a, const weighted_word *b){
int rel = strcmp( a->word, b->word );
if (rel < 0) return -1;
if (rel > 0) return 1;
return a->weight < b->weight ? -1 : a->weight > b->weight;
}
And put it to use in the merge function:
if (CompareWeightedWords( words[Rstart], words[Lstart] ) < 0)
buffer[Bindex++] = words[Rstart++];
else
buffer[Bindex++] = words[Lstart++];
I don’t think I forgot anything.

Cunit test invalid read/write of size8

Invalid read and write of size 8 happening in modify_tab_size().
what am I doing wrong? Ive tried almost everything, I dont understand it.
// Function being tested.
int erase_repeated(int *nb_words, char **words) {
for (int i = 0; i < *nb_words; ++i) {
if (words[i] != 0) {
for (int b = 0; b < *nb_words; ++b) {
if (strcmp(words[i], words[b]) == 0 && b != i)
modify_tab_size(&b, nb_words, words);
}
}
}
return *nb_mots;
}
void modify_tab_size(int *b, int *nb_words_update, char **words) {
free(words[*b]);
for (int k = *b; k < *nb_words_update; k++) {
words[k] = words[k + 1]; <--------------------------read error
words[*nb_words_update + 1] = 0; <--------------------------write error
}
(*nb_words_update)--;
(*b)--;
}
The problem is k+1 and *nb_words_update + 1 can walk off the array, and it is. Add printf("k:%d, k+1:%d, *nb_words_update + 1: %d\n", k, k+1, *nb_words_update + 1); into the loop to see.
k:1, k+1:2, *nb_words_update + 1: 4
k:2, k+1:3, *nb_words_update + 1: 4
You've only allocated three slots, 3 and 4 walk off the end of the array.
Since nb_words_update starts as the length of the array, words[*nb_words_update + 1] = 0; is always going to be too large. words[*nb_words_update] = 0; is also too large.
What you seem to be trying to do is deleting an element from an array by shifting everything after it to the left.
void delete_element(char **words, int *b, int *size) {
// Free the string to be deleted.
free(words[*b]);
// Only go up to the second to last element to avoid walking off the array.
for (int i = *b; i < *size-1; i++) {
// Shift everything to the left.
words[i] = words[i+1];
}
// Null out the last element.
// Don't use 0 for NULL, it's confusing.
words[*size-1] = NULL;
// Decrement the size of the array.
(*size)--;
// Redo the check with the newly shifted element.
(*b)--;
}
This sort of thing is better done with a linked list.
Note that your code has a bug. The result is an array of two elements, but one of them is blank. In addition to the return value of erase_repeated, also test its side effect which is to modify words. Test that words contains what you think it does.

C Sort Algorithm Not Outputting Correct Values?

new to C here. I am making a program that will sort and search a list of random ints for learning purposes, and trying to implement Bubble sort, but am getting odd results in my console during debugging.
I have an array like so:
arr[0] = 3
arr[1] = 2
arr[2] = 1
So if I was to sort this list from least to greatest, it should be in the reverse order. Instead, my sort function seems to be logically flawed, and is outputting the following.
arr[0] = 0
arr[1] = 1
arr[2] = 2
Obviously I am new because someone that knows better will probably spot my mistake very quickly.
find.c
/**
* Prompts user for as many as MAX values until EOF is reached,
* then proceeds to search that "haystack" of values for given needle.
*
* Usage: ./find needle
*
* where needle is the value to find in a haystack of values
*/
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include "helpers.h"
// maximum amount of hay
const int MAX = 65536;
int main(int argc, string argv[])
{
// ensure proper usage
if (argc != 2)
{
printf("Usage: ./find needle\n");
return -1;
}
// remember needle
int needle = atoi(argv[1]);
// fill haystack
int size;
int haystack[MAX];
for (size = 0; size < MAX; size++)
{
// wait for hay until EOF
printf("\nhaystack[%i] = ", size);
int straw = get_int();
if (straw == INT_MAX)
{
break;
}
// add hay to stack
haystack[size] = straw;
}
printf("\n");
// sort the haystack
sort(haystack, size);
// try to find needle in haystack
if (search(needle, haystack, size))
{
printf("\nFound needle in haystack!\n\n");
return 0;
}
else
{
printf("\nDidn't find needle in haystack.\n\n");
return 1;
}
}
helpers.c
#include <cs50.h>
#include "helpers.h"
#include <stdio.h>
/**
* Returns true if value is in array of n values, else false.
*/
bool search(int value, int values[], int n)
{
// TODO: implement a searching algorithm
return false;
}
/**
* Sorts array of n values.
*/
void sort(int values[], int n)
{
// TODO: implement an O(n^2) sorting algorithm
int tmp = 0;
int i = 0;
bool swapped = false;
bool sorted = false;
for (int i = 0; i < n; i++)
{
printf("%i\n", values[i]);
}
while (!sorted)
{
//check if number on left is greater than number on right in sequential order of the array.
if (values[i] > values[i+1])
{
tmp = values[i];
values[i] = values[i+1];
values[i+1] = tmp;
swapped = true;
}
if (i >= n - 1)
{
if (!swapped)
{
//No swaps occured, meaning I can assume the list is sorted.
for (int i = 0; i < n; i++)
{
printf("%i\n", values[i]);
}
sorted = true;
break;
} else {
//A swap occured on this pass through of the array. Set the flag back to false for the next pass through, repeating until no swaps are detected. (Meaning every number is in its proper place.)
i = 0;
swapped = false;
}
} else {
i++;
}
}
}
The problem is that you do the comparison and swap before you do the test if (i >= n - 1). This means that it will compare values[i] > values[i+1] when i == n-1, so it will access outside the array bounds, which is undefined behavior. In your case, there happens to be 0 in the memory after the array, so this is getting swapped into the array, and then it gets sorted to the beginning of the array.
Change
if (values[i] > values[i+1])
to
if (i < n-1 && values[i] > values[i+1])
The highest entries you can swap in an array 0..n-1 are n-2 and n-1. So i may not be larger than n-2 so i+1 accesses n-1.
Therefore your check must be:
if (i > n - 2)

Out of bounds 2D array error in C

Im stuck on this one part and I was hoping to get some help. I have a project that is basically a word search. The program reads in a file that contains the Rows and columns followed by the word search puzzle itself. You are required to create possible combinations of strings from the word search and check those combinations with a dictionary that is provided as another text document.
Here's an example of the file read in 1st is Rows and 2nd is Cols followed by the word search puzzle:
4 4
syrt
gtrp
faaq
pmrc
So I have been able to get most of the code to work except for the function that creates strings for the above file. Basically It needs to search the wordsearch and create strings, each created string gets passed on to another function to check if it's in the dictionary. However my code keeps going out of bounds when creating the strings, and it's continuing to cause Seg faults which is really frustrating.
Theses are the constants that are declared, its every possible direction to go while searching the word search puzzle for possible string combinations
const int DX_SIZE = 8;
const int DX[] = {-1,-1,-1,0,0,1,1,1};
const int DY[] = {-1,0,1,-1,1,-1,0,1};
This is the function I have to create the strings:
int strCreate(char** puzzle, char** dictionary, int n, int rows, int col){
int x, y;
int nextX, nextY, i;
char str[20] = {0};
int length = 1;
for(x = 0; x < rows; x++)
{
for(y = 0; y < col; y++)
{
//Grabs the base letter
str[0] = puzzle[x][y];
length = 1;
for(i = 0; i < DX_SIZE; i++)
{
while(length < MAX_WORD_SIZE)
{
nextX = x + DX[i]*length;
nextY = y + DY[i]*length;
// Checking bounds of next array
//This is where I'm having trouble.
if((x + nextX) < 0 || (nextX + x) > (col-1)){
printf("Out of bounds\n");
break;
}
if((y + nextY) < 0 || (nextY + y) > (rows-1)){
printf("Out of bounds\n");
break;
}
str[length] = puzzle[nextX][nextY];
//search for str in dictionary
checkStr(str, dictionary, n);
length++;
}
memset(&str[1], '\0', 19);
}
}
}
return 0;
}
I know i'm not checking the bounds properly I just can't figure out how to. When X = 1 and nextX = -1, that passes the bounds check, however say the array is at puzzle[0][0] nextX would put puzzle[-1][0] which is out of bounds causing the seg fault.
Thank you for taking the time to read, and I appreciate any help at all.
nextX and nextY are the indices used to access the array puzzle. Then the array bound check should also include the same. But the array bound check includes for example x+nextX.
// Checking bounds of next array
//This is where I'm having trouble.
if((x + nextX) < 0 || (nextX + x) > (col-1)){
printf("Out of bounds\n");
break;
}
Example:
if( nextX < 0)
printf("Out of bounds...\n");

How to find which value is closest to a number in C?

I have the following code in C:
#define CONST 1200
int a = 900;
int b = 1050;
int c = 1400;
if (A_CLOSEST_TO_CONST) {
// do something
}
What is a convenient way to check whether if a is the closest value to CONST among a,b and c ?
Edit:
It doesn't matter if I have 3 variables or an array like this (it could be more than 3 elements):
int values[3] = {900, 1050, 1400};
This works for three variables:
if (abs(a - CONST) <= abs(b - CONST) && abs(a - CONST) <= abs(c - CONST)) {
// a is the closest
}
This works with an array of one or more elements, where n is the number of elements:
int is_first_closest(int values[], int n) {
int dist = abs(values[0] - CONST);
for (int i = 1; i < n; ++i) {
if (abs(values[i] - CONST) < dist) {
return 0;
}
}
return 1;
}
See it working online: ideone
Compare the absolute value of (a-CONST), (b-CONST) and (c-CONST). Whichever absolute value is lowest, that one is closest.
Here is a generalized method. The min_element() function takes an int array, array size, and pointer to a comparison function. The comparison predicate returns true if the first values is less than the second value. A function that just returned a < b would find the smallest element in the array. The pinouchon() comparison predicate performs your closeness comparison.
#include <stdio.h>
#include <stdlib.h>
#define CONST 1200
int pinouchon(int a, int b)
{
return abs(a - CONST) < abs(b - CONST);
}
int min_element(const int *arr, int size, int(*pred)(int, int))
{
int i, found = arr[0];
for (i = 1; i < size; ++i)
{
if (pred(arr[i], found)) found = arr[i];
}
return found;
}
int main()
{
int values[3] = {900, 1050, 1400};
printf("%d\n", min_element(values, 3, pinouchon));
return 0;
}
I m adding something in Mark Byres code.....
int is_first_closest(int values[]) {
int dist = abs(values[0] - CONST),closest; //calculaing first difference
int size = sizeof( values ) //calculating the size of array
for (int i = 1; i < size; ++i) {
if (abs(values[i] - CONST) < dist) { //checking for closest value
dist=abs(values[i] - CONST); //saving closest value in dist
closest=i; //saving the position of the closest value
}
}
return values[i];
}
This function will take an array of integers and return the number which is closest to the CONST.
You need to compare your constant to every element. (works well for 3 elements but it's a very bad solution for bigger elementcount, in which case i suggest using some sort of divide and conquer method). After you compare it, take their differences, the lowest difference is the one that the const is closest to)
This answer is a reaction to your edit of the original question and your comment.
(Notice that to determine the end of array we could use different approaches, the one i shall use in this particular scenario is the simplest one.)
// I think you need to include math.h for abs() or just implement it yourself.
// The code doesn't deal with duplicates.
// Haven't tried it so there might be a bug lurking somewhere in it.
const int ArraySize = <your array size>;
const int YourConstant = <your constant>;
int values[ArraySize] = { ... <your numbers> ... };
int tempMinimum = abs(YourArray[0] - YourConstant); // The simplest way
for (int i = 1; i < ArraySize; i++) { // Begin with iteration i = 1 since you have your 0th difference computed already.
if (abs(YourArray[i] - YourConstant) < tempMinumum) {
tempMinumum = abs(YourArray[i] - YourConstant);
}
}
// Crude linear approach, not the most efficient.
For a large sorted set, you should be able to use a binary search to find the two numbers which (modulo edge cases) border the number, one of those has to be the closest.
So you would be able to achieve O(Log n) performance instead of O(n).
pseudocode:
closest_value := NULL
closest_distance := MAX_NUMBER
for(value_in_list)
distance := abs(value_in_list - CONST)
if (distance < closest_distance)
closest_value := value_in_list
closest_distance := distance
print closest_value, closest_distance

Resources