Dynamically allocated array of dynamically allocated strings - c

I'm learning C after graduation and trying to refresh old skills. I'm currently trying to make a dynamically allocated array that consist of dynamically allocated strings. Below is my code, I am trying to add an adjective to previously initialized array that has the first member as NULL. The last member should always be NULL.
char **addAdjective(char **array, const char *adjective)
{
int i = 0;
int count = 0;
while (*array != NULL){
array++;
count += 1;
}
array = (char**) realloc(*array, sizeof(*array) * (count+2));
int adjectiveLength = strlen(adjective);
array[count] = (char*) malloc(sizeof(const char)*(adjectiveLength + 1));
for (i = 0; i < adjectiveLength; i++){
array[count][i] = adjective[i];
}
array[count][i+1] = '\0';
array[count+1] = NULL;
return array;
}
When I'm calling the above with:
adjectives = addAdjective(adjectives, "beautiful");
adjectives = addAdjective(adjectives, "ugly");
adjectives = addAdjective(adjectives, "sweet");
There seems to be something wrong as when I'm trying to print the array I get nothing..
What could be wrong?
EDIT:
Print function should be okay:
void printAdjectives(char **adjectives)
{
if (!adjectives)
return;
while (*adjectives) {
printf("%s ", *adjectives);
adjectives++;
}
printf("\n");
}
And initialization:
char **initAdjectives(void)
{
char **adjectives = (char **)malloc (1 * sizeof(char *));
*adjectives = NULL;
return adjectives;
}

array[count][i+1] = '\0';
ought to be
array[count][i] = '\0';
Or better
array[count][adjectiveLength] = '\0';
Notice that when the code reaches that line i==adjectiveLength.
You allocated adjectiveLength+1 characters and writing to i+1 is past the end of the allocated space.
I don't know if that's your only error but it is illegal.

Related

Segmentation Fault when adding value into dynamic array

I wanted to add values into my. array
typedef struct teleporter {
int start;
int end;
}teleporters;
int main(int argc, char **argv) {
int lenght = 2;
teleporters *teleportPlaces;
teleporters mytele;
mytele.start = 0;
mytele.end = 0;
teleportPlaces = calloc(2, sizeof(teleporters));//malloc (sizeof(teleporters) * (lenght));
if (teleportPlaces != NULL) {
teleportPlaces = NULL;
}
for (int i = 0; i < lenght; i++) {
teleportPlaces[i] = mytele;
}
printf("Teleport END[0] = %d",teleportPlaces[0].end);
free(teleportPlaces);
return 0;
}
but everytime i add it, it gave me an segmentation error,
how do i solve this error? it'll be great if there's an article or answer about it, thanks
The problem is that you are literally throwing away the address to your teleportPlaces right after allocating it.
Remove the if statement in which you point teleportPlaces to NULL.
In the for loop, the address teleportPlaces[i] is supposed to be the address to the beginning of your array (teleportPlaces) and an offset (i). But when you reassign it to rather point to NULL, the actual address to the array is lost, leaving you with memory leakage (since you can't free a calloc if you don't know the address to it).
This if statement
if (teleportPlaces != NULL) {
teleportPlaces = NULL;
}
does not make a sense. It means that if the memory was allocated successfully you set the pointer teleportPlaces to the allocated memory to NULL, producing a memory leak.
After that you are using this null pointer in the following for loop.
Remove this if statement or for example write
if (teleportPlaces == NULL) return 0;
Or
if (teleportPlaces != NULL) {
for (int i = 0; i < lenght; i++) {
teleportPlaces[i] = mytele;
}
printf("Teleport END[0] = %d\n",teleportPlaces[0].end);
}
free( teleportPlaces );
Also you could simplify this code snippet
teleporters mytele;
mytele.start = 0;
mytele.end = 0;
the following way
teleporters mytele = { .start = 0, .end = 0 };
Also do not use magic numbers like 2. Instead of this statement
teleportPlaces = calloc(2, sizeof(teleporters));
you should write
teleportPlaces = calloc( length, sizeof(teleporters));

I attempted to parse a string into different words, attempted to freed them later but 2 of the strings have the same byte addresses

I am currently trying to parse a string into an array of strings.
So far, I currently believe I've succeeded in splitting up the string by inserting '\0' after every word "chunk".
However, when I attempt to free the string array later, some of my words have the same byte address, and thus, when I try to free one of them, the other gets freed as well.
This is the code for my parser, I apologize for its messy form:
/*
* parser()
*
* Parses a given string into different words and returns a list with the words.
* If there is a non-space and non-alphabetic character an error is recorded.
*/
void parser(char* str, char** actualList, char** freeingList,char* error, int* length){
// initialize variables
bool chara = false;
bool beginning = true;
int size = strlen(str);
bool nonAlphaSpace = false;
// iterate through the entire string
for(int i = 0; i < size; i++){
// if the character is not either a space or an alphabetic character
if(isspace(str[i])==0 && isalpha(str[i])==0 && !nonAlphaSpace){
*error = str[i];
nonAlphaSpace = true;
}
}
// if there was no irregular character
if(!nonAlphaSpace){
for(int j = 0; j < size; j++){
// if the character is the beginning of the current string
if(beginning){
// record this string into the list of words
freeingList[*length] = &str[j];
(*length)++;
// set the status of any alphabetic character being present to false;
chara = false;
// if the current character is an alphabetic character
if(isalpha(str[j])!=0){
chara = true;
}
beginning = false;
}
// if the character is a space
else if(isspace(str[j])!=0){
// if there was a character beforehand
if(chara){
// get the pointer to the next character
char* new = &str[j+1];
// change the current character to a null
str[j] = '\0';
// realign the pointer to the string to rest of the string
str = new;
j = -1;
size = strlen(str);
beginning = true;
}
}
// if the character is an alphabetic character
else{
chara = true;
}
}
// if the last chunk of string left didn't contain any characters
if(!chara){
free(str);
}
// for every word extracted
for(int k = 0; k < *length; k++){
int newSize = strlen(freeingList[k]);
bool first = true;
// get the pointer to the first character in the word, i.e. not the first few spaces
for(int l = 0; l < newSize; l++){
if(isspace(freeingList[k][l])==0 && first){
actualList[k] = &freeingList[k][l];
first = false;
}
}
}
}
}
This is when I attempt to free it:
// free the current collection of strings
for(int j = 0; j < size; j+=2){
free(words[j]);
}
When I input "home or for" into the parser and later try to free it, the address of "home" is 0x7fffffffe840 while the address of "for" is 0x7fffffffe848. This leads me to believe that the freeing of home also frees or causing a SIGABRT error later.
Is this assumption correct? How can I overcome this double freeing?
You should only call free() on pointers returned by malloc(), calloc(), or realloc(). What it looks like you are doing:
char *ptr = malloc(100);
char *ptr2 = &ptr[10];
free(ptr2); // You can't do that.
I suspect you meant to make a copy of the strings. Here's a simplified version:
void parser(char* str, char** actualList, int* length) {
char *start = str; // The start of the current string
int count = 0; // Number of strings copied
while (*str) {
if (isspace(*str)) {
*str = '\0';
actualList[count] = malloc(strlen(start) + 1); // Allocate space for string
strcpy(actualList[count++], start); // Copy string
start = str + 1; // Reset for next string
if (count == *length - 1) break; // Don't overflow pointer array
}
str++;
}
// Grab the final string
actualList[count] = malloc(strlen(start) + 1); // Allocate space for string
strcpy(actualList[count++], start); // Copy string
*length = count;
}
Then call it like:
char input[] = "home or for";
char *words[5];
int max_words = 5;
parser(input, words, &max_words);
// max_words should be 3 now
for (int i = 0; i < max_words; i++) {
printf("%s\n", words[i]);
}
// Clean up
for (int i = 0; i < max_words; i++) {
free(words[i]);
}
Output:
home
or
for
That's not a parser, though. More a tokenizer.
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
bool parser(char const *str, char ***words, size_t *num_words, size_t *error)
{ // ^^^ gaaaah! *)
assert(words);
errno = 0;
size_t length = strlen(str);
for (size_t i = 0; i < length; ++i) {
if (!isalnum(str[i]) && !isspace(str[i])) {
*error = i; // the position is most likely more meaningful than the character
return false; // get outta here!!
}
}
char const *begin;
char const *end;
*num_words = 0;
*words = NULL;
bool in_word = false;
for (size_t i = 0; i <= length; ++i) {
if (!in_word && isalnum(str[i])) { // word begins
begin = str + i;
in_word = true;
}
else if (in_word && !isalnum(str[i])) { // word ended
end = str + i;
char *word = calloc(end - begin + 1, sizeof *word);
if (!word) {
for (size_t i = 0; i < num_words; ++i)
free((*words)[i]);
free(*words);
errno = ENOMEM;
return false;
}
memcpy(word, begin, end - begin);
char **tmp = realloc(*words, (*num_words + 1) * sizeof *tmp);
if (!tmp) {
free(word);
for (size_t i = 0; i < num_words; ++i)
free((*words)[i]);
free(*words);
errno = ENOMEM;
return false;
}
*words = tmp;
tmp[(*num_words)++] = word;
in_word = false;
}
}
return true;
}
int main(void)
{
char const *foo = "slfkja askdfj jk j aksjf lasjdflkjsdlf jask fdjl";
char **words = NULL;
size_t num_words = 0;
size_t error = 0;
if (!parser(foo, &words, &num_words, &error)) {
if (errno == ENOMEM)
fputs("Not enough memory. :(\n\n", stderr);
else fprintf(stderr, "Error at position %zu: \"%s\"\n\n", error, foo + error);
return EXIT_FAILURE;
}
puts("List of words:");
for (size_t i = 0; i < num_words; ++i) {
printf("\"%s\"\n", words[i]);
free(words[i]);
}
free(words);
}
C should be renamed brainf*ck ...
*) Three Star Programmer
you modify the value of str in the body of the function (in the line str = new; (don't use new as an identifier, more if you plan to use this code as C++ code, as new is a reserved word in C++). As you don't call malloc(3) in the function body, it's quite normal you get a problem from free(3), as free requires to be passed a pointer previously generated with malloc (and only once, so you cannot call it twice with the same pointer). This is the reason of you getting SIGABRT and the like. As a general rule, don't call free(3) in a function you don't also call malloc for the same pointer. That use is error prone and you will run into trouble more than once a day if you insist in doing everything in a single function.
better than apologize for the messy form of the code, please, clean it before posting. Post a minimu (meaning the minimum code that shows the error), full (meaning that we can compile it and observe the result you post as failing), verifiable (code that shows it producing the observed result, and not the expected one) and complete (this means we have nothing to do but compile it and run) code (so we can test it failing as you say, without having to correct it first) That way, we can make a diagnostic of what happens in your code. If we need to correct the code just to make it runnable, we can correct the main problem you are observing and be unable to see the mistake. You see? :)
Note about using new as an identifier in C code:
Many Unit Testing frameworks require your code to be compilable as C++ code, so it can be used by the framework (at least Google Test requires this) If you plan to write unit tests for your code, remember that new is a reserved word in C++ for the operator new, and so, your code will produce syntax errors if you try to compile it with a c++ compiler. Better if you don't use it.

Problem freeing memory from multidimensional array in C, free() crashes program

I am creating a deque to store stings in C, and when I call the free() function, the program crashes. I have implemented a similar structure but only storing integers, and encountered no problems, but this seems to be causing me a few. I created a struct containing a multidimensional array or characters, and i think maybe I am not using the pointers correctly? I have searched far and wide and cannot solve it The main area of concern is when i call clear() from the ain body. That in turn calls free(), and the program just stalls. :-( Any help would be extremely useful.
#include <stdio.h>
#define MAX 20 // number of characters for word
typedef struct {
char **deque;
int size;
int pFront;
int pRear;
} deque;
typedef int bool;
enum { false, true };
void initDeque(deque *d, int initialSize)
{
d->size = initialSize;
d->pFront = -1;
d->pRear = -1;
d->deque = (char **)malloc(sizeof(char*)*initialSize);
int idx;
for(int idx = 0; idx < d->size; idx++)
{
d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));
d->deque[idx] = "";
}
printf("d->size: %zu\n", d->size);
}
void clear(deque *d) {
if(d->pFront == -1)
{
printf("Queue is empty\n");
}
else
{
printf("Attempting to clear...\n");
for(int idx = 0; idx < d->size; idx++)
{
printf("Attempting to clear columns...");
free(d->deque[idx]);
}
printf("Attempting to clear rows...");
free(d->deque);
printf("Freed!!!!\n");
d->deque = NULL;
d->size = 0;
d->pFront = -1;
d->pRear = -1;
}
}
bool isEmpty(deque *d)
{
if(d->pFront == -1){
return true;
}
else
{
return false;
}
}
bool isFull(deque *d)
{
if(d->size == d->pRear+1)
{
return true;
}
else
{
return false;
}
}
void display(deque *d)
{
if(isEmpty(d)){
printf("empty\n");
}
else{
printf("Deque Values:\n");
int idx;
for(int idx = 0; idx <= d->pRear; idx++)
{
printf("Index: %zu\tValue: %s\n", idx, d->deque[idx]);
}
printf("Size: %zu\n", d->size);
}
}
void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{
if(isFull(d))
{
printf("Is Full\n");
int idx;
deque dTemp;
initDeque(&dTemp, d->size);
printf("dTemp Initialised\n");
for(idx = 0; idx < d->size; idx++)
{
dTemp.deque[idx] = d->deque[idx];
}
printf("deque copied to dTemp:\n");
for(idx = 0; idx < d->size; idx++)
{
printf("dTemp[%zu]: %s\n", idx, dTemp.deque[idx]);
}
clear(&d);
printf("d cleared\n");
initDeque(&d, dTemp.size*2);
printf("New deque of double length initialised\n");
for(idx = 0; idx < dTemp.size; idx++)
{
d->deque[idx] = d->deque[idx];
}
printf("dTemp Copied to new deque\n");
clear(&dTemp);
printf("dTemp Cleared\n");
char **tmp = realloc( d->deque, sizeof (d->deque) * (d->size*2) );
if (tmp)
{
d->deque = tmp;
for (int i = 0; i < d->size; i++)
{
d->deque[d->size + i] = malloc( sizeof(char) * MAX );
}
}
}
printf("Appending to rear.. %s\n", item);
d->pRear++;
d->deque[d->pRear] = item;
if(d->pFront == -1)
d->pFront = 0;
}
int main(void)
{
deque d;
initDeque(&d, 5);
rAppend(&d, "when");
rAppend(&d, "will");
rAppend(&d, "wendy");
rAppend(&d, "walk");
rAppend(&d, "with");
display(&d);
clear(&d);
return 0;
}
The problem is your are calling free() on static chain "when", "will",...
You can replace insertion in the function void rAppend(deque *d, char item[]) :
d->deque[d->pRear] = item;
with:
d->deque[d->pRear] = strdup(item);
Doing like this chains are allocated in the heap and free from the heap.
After there is others problems in the code, but it run without crash.
The main problem seems to be that you don't appreciate the difference between copying / assigning pointers and copying / assigning the data to which they point. Secondarily, it seems you may not appreciate the utility of pointers that don't point to anything, especially null pointers. Some details follow.
You are dynamically allocating space for a bunch of strings ...
for(int idx = 0; idx < d->size; idx++)
{
d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));
... and then leaking all of that space by replacing the pointer to each with a pointer to an empty string literal:
d->deque[idx] = "";
}
As if the leak were not bad enough, you are not permitted to free a string literal or modify its content, which you nevertheless try to do to any of those pointers that remain in the dequeue whenever you clear() it. This is likely the cause of some of your errors.
If you want to set each allocated string to an empty one then modify its content instead of replacing the pointer to it. For example:
d->deque[idx][0] = '\0';
In fact, however, you probably don't need to do even that. You are already performing bookkeeping to know which arrays contain valid (string) data and which don't, and that should be sufficient to do the right thing. Supposing you maintain copies of the strings in the first place.
But that's not all. When you rAppend() elements to your deque you have a similar problem. You create a temporary deque, and then copy the string pointers from your original deque into the temporary:
dTemp.deque[idx] = d->deque[idx];
Not only does this leak the original (empty) data in the temporary deque, it aliases that deque's contents with the main deque's. When you later clear the temporary deque, therefore, you free all the string pointers in the original. Subsequently using or freeing them produces undefined behavior.
Perhaps you instead want to strcpy() all the elements of the main deque into the temp and back, but I suggest instead skipping the temp deque altogether with something along these lines:
void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{
if(isFull(d))
{
printf("Is Full\n");
char **tmp = realloc(d.deque, d->size * 2);
if (tmp)
{
d->deque = tmp;
for (int i = 0; i < d->size; i++)
{
// Copied from the original, but see below
d->deque[d->size + i] = malloc( sizeof(char) * MAX );
}
d->size * 2;
} // else?
}
printf("Appending to rear.. %s\n", item);
d->pRear++;
// Oops, this is another leak / aliasing issue:
d->deque[d->pRear] = item;
if(d->pFront == -1)
d->pFront = 0;
}
The whole point of the temporary deque is lost on me, since the realloc() you need to do preserves the original data anyway (as long as it succeeds, anyway).
Note too, however, that this still has an aliasing issue: you have aliased a deque element with the appended string, and leaked the memory allocated for that element. Furthermore, when you clear the deque, you free that string for everyone holding a pointer to it. Or at least you attempt to do so. You're not permitted to do that to string literals.
I suggest not allocating space in your deque for the individual strings at all, and not freeing it. Continue to use assignment to store elements in your deque, understanding and embracing that these are aliases. This will be more analogous to your implementation for ints.
#include<memory>
#include<iostream>
using namespace std;
struct S {
S() { cout << "make an S\n"; }
~S() { cout << "destroy an S\n"; }
S(const S&) { cout << "copy initialize an S\n"; }
S& operator=(const S&) { cout << "copy assign an S\n"; }
};
S* f()
{
return new S; // who is responsible for deleting this S?
};
unique_ptr<S> g()
{
return make_unique<S>(); // explicitly transfer responsibility for deleting this S
}
int main()
{
cout << "start main\n";
S* p = f();
cout << "after f() before g()\n";
// S* q = g(); // this error would be caught by the compiler
unique_ptr<S> q = g();
cout << "exit main\n";
// leaks *p
// implicitly deletes *q
}

How to convert from string array to int array and then sort it using c

I have string array initialized like that:
char ** strArray;
if ( (strArray = malloc(sizeof(*strArray) + 3)) == NULL ) {
fprintf(stderr, "ls1: couldn't allocate memory");
//exit(EXIT_FAILURE);
}
strArray[0] = NULL;
strArray[0] = "111";
strArray[1] = "222";
strArray[2] = "1";
strArray[3] = "2";
I want to convert this string array to int array, like that:
int * toIntArray(char ** strArray) {
int size = getCharArraySize(strArray);
int intArray[size];
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return intArray;
}
int getCharArraySize(char ** strArray) {
int s = 0;
while ( strArray[s]) {
printf("Char array: %s.\n", strArray[s]);
s++;
}
return s;
}
And then I want to sort this int array.
I must have string array initilized like above (char ** strArray) and then convert this to int array and then sort it. Can anybody help my with that? I would ask about printed sorted integer in main function.
A few minor things to take note of in the question code:
char ** strArray;
if ( (strArray = malloc(sizeof(*strArray) + 3)) == NULL ) {
fprintf(stderr, "ls1: couldn't allocate memory");
//exit(EXIT_FAILURE);
}
If successful, the intention of the above code allocates memory to strArray sufficient for three char *'s. Specifically, strArray[0], strArray1 and strArray[2].
NOTE: As pointed out in Matt McNabb's comment below, it actually incorrectly allocates memory sufficient for one char *, and three extra bytes.
strArray[0] = NULL;
The above line sets sets the first pointer in the **strArray to point at NULL.
strArray[0] = "111";
The above code is odd. After just setting strArray[0] to point at NULL, the above line changes it to point to "111". Kind of makes setting it to NULL (in the first place) seem unnecessary.
strArray[1] = "222";
strArray[2] = "1";
The above two lines initialize the other two pointers in the strArray correctly.
strArray[3] = "2";
The above line attempts to initialize strArray[3], when that element of the array really doesn't exist. So, it is changing something to point to "2", but probably not with the expected result.
Perhaps the intent would be better served by changing the above code to:
char **strArray;
size_t strArrayElements=4;
if(NULL == (strArray = malloc((strArrayElements+1) * sizeof(*strArray))))
{
fprintf(stderr, "ls1: couldn't allocate memory");
exit(EXIT_FAILURE);
}
strArray[strArrayElements] = NULL;
strArray[0] = "111";
strArray[1] = "222";
strArray[2] = "1";
strArray[3] = "2";
As can be observed, the above code allocates 5 elements (strArrayElements+1) to the **strArray. The last element strArray[4] is initialized to NULL; a marker to indicate End-Of-List. Then the other 4 elements [0..3] are initialized.
Now shifting focus to:
int * toIntArray(char ** strArray) {
int size = getCharArraySize(strArray);
int intArray[size];
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return intArray;
}
The above code is successful at converting the strings to their integer forms, and storing them in intArray. However, the code is flawed when it attempts to return intArray to the caller. The intArray variable was declared as a local stack object. The return statement causes all such stack variables to become invalid; and allows the stack memory such variables were using to be used for other things.
Perhaps the the following code better represents what was intended. It allocates memory from the heap for intArray. This allocated memory can outlive the return statement:
int *toIntArray(char **strArray)
{
int size = getCharArraySize(strArray);
int *intArray = malloc(size * sizeof(*intArray));
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return(intArray);
}
Spoiler code may be found here.

using functions in c (return value)

Learning C and having many doubts.
I have a function (lets say function 1) that calls another function (lets say function 2).
Function 2 calculates an array of string.
How can I use this array in function 1?
Some code example:
int find_errors(char* word)
{
char error[100];
/*Given the word, It will find the duplicate chars and store it in the
error array. */
return 0;
}
int find_word(char* word)
{
find_errors (word);
printf("%s\n", error);
return 0;
}
There are at least three possible approaches:
Use a global variable
pass a parameter between them
return a pointer from the function
There are multiple ways to do this.
1) Create a dynamic array and return a pointer to the array. This will require you to manually free the memory for the array at a later time.
#define NUM_ELEMS 50
// In find_error():
char* error = malloc(NUM_ELEMS * sizeof(char));
return error;
// In find_word():
char *error = find_errors();
// do stuff
free(error);
2) Pass a pointer to find_errors that it can use as the error array. This will not require you to manually free the memory.
// In find_word():
char error[NUM_ELEMS];
find_error(error);
3) Use a global array. May make it more difficult for other people to understand your code. Has other potential problems as well.
// In global scope:
char error[NUM_ELEMS];
Your question relates to "call-by-reference" and "call-by-value".
char* getNewValsToSet(void)
{
char* new_vals = (char*) malloc(sizeof(char[5]));
new_vals[4] = '\0';
return new_vals;
}
void setValuesEven(char* vals_to_set)
{
vals_to_set[0] = 'A';
vals_to_set[2] = 'C';
}
void setValuesOdd(char* vals_to_set)
{
vals_to_set[1] = 'B';
vals_to_set[3] = 'D';
}
int main(void)
{
char* some_vals_to_set = getNewValsToSet();
setValsEven(some_vals_to_set);
setValsOdd(some_vals_to_set);
// ... now has vals "ABCD"
free(some_vals_to_set); //cleanup
return 0;
}
If you have "doubts" about learning C, IMHO it's one of the best things you can do (no matter the language in which you work) because it will explain exactly how things work "under-the-hood" (which all high-level languages try to hide to some degree).
You need to declare the error array globally and use it just like you did.
EDIT: using global variables isn't the best practice in most of the cases, like this one.
Here is an example of what you are looking for with an awesome console output. It dynamically allocates the array to hold any number errors (duplicate characters in your case) that may occur.
//Only free errors if result is > 0
int find_errors(char* word, char** errors)
{
int num_errors = 0;
int word_length = strlen(word);
int ARRAY_SIZE = MIN(8, word_length);
char existing[word_length];
int existing_index = 0;
*errors = NULL;
for(int i = 0; i < word_length; i++)
{
char character = word[i];
//Search array
for (int n = 0; n < word_length; ++n ) {
if(n >= existing_index)
{
existing[n] = character;
existing_index++;
break;
}
if (existing[n] == character) {
num_errors++;
if(!*errors)
*errors = (char*)malloc(ARRAY_SIZE * sizeof(char));
//Check if we need to resize array
if(num_errors >= ARRAY_SIZE)
{
ARRAY_SIZE *= 2;
ARRAY_SIZE = MIN(ARRAY_SIZE, word_length);
char *tmp = (char*)malloc(ARRAY_SIZE * sizeof(char));
memcpy(tmp, *errors, (unsigned long)ARRAY_SIZE);
free(*errors);
*errors = tmp;
}
//Set the error character
(*errors)[num_errors - 1] = character;
break;
}
}
}
return num_errors;
}
int find_word(char* word)
{
char* errors;
int errCount = find_errors (word, &errors);
if(errCount > 0)
{
printf("Invalid Characters: ");
for(int i =0; i < errCount; i++)
{
printf("%c ", errors[i]);
}
printf("\n");
free(errors);
}
return 0;
}
int main(int argc, char *argv[])
{
find_word("YWPEIT");
find_word("Hello World");
find_word("XxxxXXxXXoooooooOOOOOOOOOOOOOOOooooooooOOOOOOOOOOOOooooooOOO");
}

Resources