Copying elements from array by file - arrays

I am fetching the data from file line by line and storing them in word array
i want to copy the whole word into another array like if wrd has assssh in current iteration i want it whole to be copied to arr array
but what is been doing the first element in each iteration is copied in arr[i] but that is not what i want
i want the whole word to be copied at each index, actually after that i am sorting the word according to first alphabet in each array please help out
while (fscanf(file, " %1023s", wrd) == 1) {
printf("%s\n", wrd);
//Pushing the result into vector
//strcpy(arr,wrd);
arr[i]=wrd[0];
i++;
counter++;
}
bubbleSortAWriteToB(arr, s_arr);

Assumeing 'arr' is a two dimentional array and 'wrd' is a character array, your code should look something like below in order to achieve what you want:
while (fscanf(file, " %1023s", wrd) == 1) {
printf("%s\n", wrd);
// calculating length of the wrd array
int wrd_length = (int)( sizeof(wrd) / sizeof(wrd[0]);
int idx = 0;
while(idx < wrd_length) {
arr[i][idx] = wrd[idx];
idx++;
}
i++;
counter++;
}

Related

Optimizing a do while loop/for loop in C

I was doing an exercise from LeetCode in which consisted in deleting any adjacent elements from a string, until there are only unique characters adjacent to each other. With some help I could make a code that can solve most testcases, but the string length can be up to 10^5, and in a testcase it exceeds the time limit, so I'm in need in some tips on how can I optimize it.
My code:
char res[100000]; //up to 10^5
char * removeDuplicates(char * s){
//int that verifies if any char from the string can be deleted
int ver = 0;
//do while loop that reiterates to eliminate the duplicates
do {
int lenght = strlen(s);
int j = 0;
ver = 0;
//for loop that if there are duplicates adds one to ver and deletes the duplicate
for (int i = 0; i < lenght ; i++){
if (s[i] == s[i + 1]){
i++;
j--;
ver++;
}
else {
res[j] = s[i];
}
j++;
}
//copying the res string into the s to redo the loop if necessary
strcpy(s,res);
//clar the res string
memset(res, '\0', sizeof res);
} while (ver > 0);
return s;
}
The code can't pass a speed test that has a string that has around the limit (10^5) length, I won't put it here because it's a really big text, but if you want to check it, it is the 104 testcase from the LeetCode Daily Problem
If it was me doing something like that, I would basically do it like a simple naive string copy, but keep track of the last character copied and if the next character to copy is the same as the last then skip it.
Perhaps something like this:
char result[1000]; // Assumes no input string will be longer than this
unsigned source_index; // Index into the source string
unsigned dest_index; // Index into the destination (result) string
// Always copy the first character
result[0] = source_string[0];
// Start with 1 for source index, since we already copies the first character
for (source_index = 1, dest_index = 0; source_string[source_index] != '\0'; ++source_index)
{
if (source_string[source_index] != result[dest_index])
{
// Next character is not equal to last character copied
// That means we can copy this character
result[++dest_index] = source_string[source_index];
}
// Else: Current source character was equal to last copied character
}
// Terminate the destination string
result[dest_index + 1] = '\0';

Recursion problems in C

I am working on an anagram solver in C. Hit a problem where the solver will return the first few anagrams correctly, however on ones that extend past 2 words, it begins to enter an infinite loop.
Example:
I enter "team sale rest" into the anagram solver, it responds with teamster ale, and a few others. Then when it arrives at releases, it enters an infinite loop where it prints "releases am matt" "releases am am matt" etc.
Here is the code base:
//recursively find matches for each sub-word
int findMatches(char string[], char found_so_far[])
{
printf("String entering function: %s\n", string);
int string_length = strlen(string);
int_char_ptr *results = getPowerSet(string, string_length);
if(!results)
return 2;
// selects length of subset, starting with the largest
for (int i = string_length - 1; i > 0; i--)
{
// iterates through all the subsets of a particular length
for(int j = 0; j < results->count[i]; j++)
{
word_array *matches = NULL;
// check words against dictionary
matches = dictionary_check(results->table[i][j]);
if (matches)
{
// iterate through matches
for(size_t k = 0; k < matches->size; k++)
{
int found_length;
// find out length of string needed for found
if (strcmp(found_so_far, "") == 0)
found_length = strlen(matches->arr[k]) + 1;
else
found_length = strlen(found_so_far) + strlen(matches->arr[k]) + 2;
char found[found_length];
// on first passthrough, copy directly from matches
if (strcmp(found_so_far, "") == 0)
strcpy(found, matches->arr[k]);
else
sprintf(found, "%s %s", found_so_far, matches->arr[k]);
char tempstr[string_length];
strcpy(tempstr, string);
char *remain = get_remaining_letters(tempstr, results->table[i][j]);
// if there are no letters remaining
if (strcmp(remain, "") == 0)
{
printf("MATCH FOUND: %s \n", found);
// alternatively, could store strings to array
}
else
{
findMatches(remain, found);
}
}
}
}
free(results->table[i][results->count[i] - 1]);
free(results->table[i]);
}
return 0;
}
How I read it (I am obviously missing something) is that it should try to match all matches, and if it can't , it should move to the next subset of letters found.
I have tries going through with a debugger, and cant make rhyme or reason of it.
As mentioned above in the commment:
get_remaining_letters used the original results->table[i][j] and removed the letters. This would leave an empty string for the next iteration and cause it to not perform as expected. Fixed by copying the string to a temporary one inside that function.

Right algorithm but wrong implementation?

I am a beginner in C with some experience in python and java. I want to solve a problem with C. The problem goes like this:
Take an input as a sentence with words separated by blank spaces only (assume lower case only), re-write the sentence with the following rules:
1) If a word occurs the first time, keep it the same.
2) If the word occurs twice, replace the second occurrence with the word being copied twice (e.g. two --> twotwo).
3) If the word occurs three times or more, delete all the occurrences after the second one.
Print the output as a sentence. The maximum lengths of the input sentence and each individual word is 500 chars and 50 chars.
Exemplary input: jingle bells jingle bells jingle all the way
Exemplary output: jingle bells jinglejingle bellsbells all the way
The approach I take is:
1) Read the input, separate each word and put them into an array of char pointers.
2) Use nested for loop to go through the array. For each word after the first word:
A - If there is no word before it that is equal to it, nothing happens.
B - If there is already one word before it that is equal to it, change the word as its "doubled form".
C - If there is already a "doubled form" of itself that exists before it, delete the word (set the element to NULL.
3) Print the modified array.
I am fairly confident about the correctness of this approach. However, when I actually write the code:
'''
int main()
{
char input[500];
char *output[500];
// Gets the input
printf("Enter a string: ");
gets(input);
// Gets the first token, put it in the array
char *token = strtok(input, " ");
output[0] = token;
// Keeps getting tokens and filling the array, untill no blank space is found
int i = 1;
while (token != NULL) {
token = strtok(NULL, " ");
output[i] = token;
i++;
}
// Processes the array, starting from the second element
int j, k;
char *doubled;
for (j = 1; j < 500; j++) {
strcpy(doubled, output[j]);
strcat(doubled, doubled); // Create the "doubled form"
for (k = 0; k < j; k++) {
if (strcmp(output[k], output[j]) == 0) { // Situation B
output[j] = doubled;
}
if (strcmp(output[k], doubled) == 0) { // Situation C
output[j] = ' ';
}
}
}
// Convert the array to a string
char *result = output[0]; // Initialize a string with the first element in the array
int l;
char *blank_space = " "; // The blank spaces that need to be addded into the sentence
for (l = 1; l < 500; l++) {
if (output[l] != '\0'){ // If there is a word that exists at the given index, add it
strcat(result, blank_space);
strcat(result, output[l]);
}
else { // If reaches the end of the sentence
break;
}
}
// Prints out the result string
printf("%s", result);
return 0;
}
'''
I did a bunch of tests on each individual block. There are several issues:
1) When processing the array, strcmp, strcat, and strcpy in the loop seem to give Segmentation fault error reports.
2) When printing the array, the words did not show the order that they are supposed to do.
I am now frustrated because it seems that the issues are all coming from some internal structural defects of my code and they are very much related to the memory mechanism of C which I am not really too familiar with. How should I fix this?
One issues jumps out at me. This code is wrong:
char *doubled;
for (j = 1; j < 500; j++) {
strcpy(doubled, output[j]);
strcat(doubled, doubled); // Create the "doubled form"
doubled doesn't point to any actual memory. So trying to copy data to where it points is undefined behavior and will almost certainly cause a SIGSEGV - and it will corrupt memory if it doesn't cause a SIGSEGV.
That needs to be fixed - you can't copy a string with strcpy() or strcat() to an pointer that doesn't point to actual memory.
This would be better, but still not ideal as no checking is done to ensure there's no buffer overflow:
char doubled[ 2000 ];
for (j = 1; j < 500; j++) {
strcpy(doubled, output[j]);
strcat(doubled, doubled); // Create the "doubled form"
This is also a problem with doubled defined like that:
if (strcmp(output[k], output[j]) == 0) { // Situation B
output[j] = doubled;
}
That just points output[j] at doubled. The next loop iteration will overwrite doubled, and the data that output[j] still points to to will get changed.
This would address that problem:
if (strcmp(output[k], output[j]) == 0) { // Situation B
output[j] = strdup( doubled );
}
strdup() is a POSIX function that, unsurprising, duplicates a string. That string will need to be free()'d later, though, as strdup() is the same as:
char *strdup( const char *input )
{
char *duplicate = malloc( 1 + strlen( input ) );
strcpy( duplicate, input );
return( duplicate );
}
As pointed out, strcat(doubled, doubled); is also a problem. One possible solution:
memmove(doubled + strlen( doubled ), doubled, 1 + strlen( doubled ) );
That copies the contents of the doubled string to the memory starting at the original '\0' terminator. Note that since the original '\0' terminator is part of the string, you can't use strcpy( doubled + strlen( doubled ), doubled );. Nor can you use memcpy(), for the same reason.
Your code invokes undefined behavior in several places by writing to memory that is not yet owned, and is likely the cause of the segmentation fault you are seeing. For example, in this segment:
char *result = output[0]; // Initialize a string with the first element in the array
int l;
char *blank_space = " "; // The blank spaces that need to be addded into the sentence
for (l = 1; l < 500; l++) {
if (output[l] != '\0'){ // If there is a word that exists at the given index, add it
strcat(result, blank_space);
strcat(result, output[l]);
By itself...
char *result = output[0]; //creates a pointer, but provides no memory.
...is not sufficient to receive content such as
strcat(result, blank_space);
strcat(result, output[l]);
It needs memory:
char *result = malloc(501);//or more space if needed.
if(result)
{
//now use strcat or strcpy to add content

Writing a function to split a string

I'm trying to write a function to split a string (not use strtok) to learn how it works. I've come up with the following so far:
char ** split_string(char * string, char sep) {
// Allow single separators only for now
// get length of the split string array
int array_length = 0;
char c;
for (int i=0; (c=string[i]) != 0; i++)
if (c == sep) array_length ++;
// allocate the array
char * array[array_length + 1];
array[array_length] = '\0';
// add the strings to the array
for (int i=0, word=0; (c=string[i]) != 0;) {
if (c == sep) {
i=0;
word ++;
} else {
array[i][word] = c;
i++;
}
}
return array;
}
This is my first time working with a pointer to a pointer (a list of strings), so I'm a bit unclear how to do this, as you can probably tell from the above function.
How would this be properly done? Specifically, is the return type correct? How would you add the \0 to the end of the array?
the one mistake you are making is not allocating space for the words to be copied. You must explicitly allocate space for the words in the destination array before copying. Following program achieves what's intended. To know the number of words, declare array_length to be a global variable, so that you can use that in the function where split_string was called.
int array_length=0;
char** split_string(char* str, char sep){
for(int i = 0;str[i] != '\0';++i){
if(str[i] == sep) ++array_length;
char** str_arr = (char**)malloc(sizeof(char*) * (array_length+1));
for(int i=0, j, k = 0; str[i] != '\0'; ++k){ // k is used to index the destination array for the extracted word
for(j = i; str[j] != sep && str[j] != '\0'; ++j); // from the current character, find the position of the next separator
str_arr[k] = (char*)malloc((j-i+2)*sizeof(char)); // Allocate as many chars in the heap and make str_arr[k] pointer point to it
strncpy(str_arr[k], str+i, j-i); // copy the word to the allocated space
i=j+1; // move the array iterator to the next non-sep character
}
return str_arr;
}
If you don't want to use malloc explicitly, you can also use library function strndup which takes the pointer to the start character of the source string and number of characters to be copied as input and does the memory allocation, copies the word and returns the pointer to the allocated space. so two of the lines in the function
str_arr[k] = (char*)malloc((j-i+2)*sizeof(char)); // Allocate as many chars in the heap and make str_arr[k] pointer point to it
strncpy(str_arr[k], str+i, j-i);
can be replaced by a single line as-
str_arr[k] = strndup(str+i, j-i);
But I would recommend using the first method as a beginner for better understanding and debugging.
Note: The above program works only for single delimiter between words, if there is an occurrence of multiple consecutive delimiters between words, you will have to tweak the program a bit in order to get it working.

C - Can't add elements to a char array

void initializeEncryptArray(char key[], char encrypt[])
{
int i = 0, j = 90;
char *endkey = removeDuplicates(key);
printf("%s\n", endkey);
while((int)endkey[i] != 0){
encrypt[i] = endkey[i];
i++;
}
while(j >= 65){
if (targetFound(encrypt, i, (char)j) != 0){
encrypt[i] = (char)j;
i++;
}
j--;
}
printf("Finished encryption.\n");
printf("%c\n", encrypt[0]);
}
So here's my code, and I'm trying to take characters in the key, remove all duplicates (which works), and then add them to a final encrypt char array. Then add the rest of the alphabet in reverse order to the same array. However, when I print the first character in the array, it's empty. endkey is filled, and it gets to the end, but the actual encrypt array is empty. What am I doing wrong? Any help would be appreciated.

Resources