Copying strings of equal length to new string array - c

I have a dictionary of words stored in a 2D char array. I also have a scanned word stored in a structure. I'm trying to 'thin down' my main dictionary by copying words of length equal to the scanned word into a seperate 2D array. Then I want to print the new array out.
i.e if scanned word = hello, all words of the same length will be copied into the new array.
My code just prints the first word of the array infinitely
words.startword is the scanned word.
void get_equal_length (char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0;
for (i = 0; dictionary[i] != '\0'; i++)
{
if (strlen(*dictionary) == strlen(words.startword))
{
strcpy(*equal_length_dictionary, *dictionary);
word_count++;
printf("Word #%d: %s\n", word_count, *equal_length_dictionary);
}
}
printf("Equal length words: %d\n", word_count);
}

for (i = 0; dictionary[i] != '\0'; i++)
{
if (strlen(dictionary) == strlen(words.startword))
{
strcpy(*equal_length_dictionary, *dictionary);
should be:
for (i = 0; dictionary[i][0] != '\0'; i++)
{
if (strlen(dictionary[i]) == strlen(words.startword))
{
strcpy(equal_length_dictionary[i], dictionary[i]);
Also, to improve speed, better calculate strlen(words.startword) only once before the loop, instead of recalculating it inside the loop at each iteration. You should also not forget to terminate the new array with a null string.
The full code will be:
void get_equal_length(char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0, len = strlen(words.startword);
for (i = 0; dictionary[i][0] != '\0'; i++)
{
if (strlen(dictionary[i]) == len)
{
strcpy(equal_length_dictionary[i], dictionary[i]);
word_count++;
printf("Word #%d: %s\n", word_count, equal_length_dictionary[i]);
}
}
// now we will also terminate the new array with a null string
equal_length_dictionary[i][0] = '\0';
printf("Equal length words: %d\n", word_count);
}

This should work, although not tested. As Kevin mentioned in the comment, you need to use the index i in the loop. You also should use word_count as index:
void get_equal_length (char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0;
for (i = 0; i < MAX_WORDS; i++)
{
char* cur_word = dictionary[i];
if (!cur_word || !*cur_word)
break;
if (strlen(cur_word) == strlen(words.startword))
{
strcpy(equal_length_dictionary[word_count], cur_word);
word_count++;
printf("Word #%d: %s\n", word_count, equal_length_dictionary[word_count]);
}
}
printf("Equal length words: %d\n", word_count);
}

Related

Concatenating a string and numbers in C

I have a program that has to count the number of duplicate characters in a string. For example "aaabcc" should return "a3b1c2" and "aaabcccc..a" should return "a3b1c4.2a1". I am currently using sprintf to concatenate the string and numbers like this: sprintf(s, "%s%c%d", s, prev, count);, where s is the string containing the result. But that causes an error since I am using "s" as an input and also as the destination. Is there some way around this?
This is my code right now:
char *s = (char *)malloc(sizeof(char) * 100);
char prev = argv[1][0];
if(isdigit(prev)!=0){
printf("%s","ERROR");
return 0;
}
int count = 1;
for(int i=1; i<strlen(argv[1]); i++){
if(isdigit(argv[1][i])!=0){
printf("%s","ERROR");
return 0;
}
//check if same as previous letter
if(prev==argv[1][i]){
count++;
}else{
//add letter and count to string
//problem
sprintf(s, "%s%c%d", s, prev, count);
count = 1;
}
//update prev
prev=argv[1][i];
}
//add it to string
//problem
sprintf(s, "%s%c%d", s, prev, count);
//check if result is smaller than input
if(strlen(s) > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
printf("%s\n", s);
}
free(s);
Use a different buffer for sprintf(), then concatenate to s with strcat().
Make sure you initialize s to an empty string after allocating it.
Instead of allocating a hard-coded size for s, allocate a string big enough for the worst case (every character repeated just once, so it's a1b1c1...).
temp can be a short, fixed-size string, since it just has to hold the length of one run.
char *s = malloc(strlen(argv[1]) * 2 + 1);
s[0] = '\0';
char temp[20];
char prev = argv[1][0];
if(isdigit(prev)!=0){
printf("%s","ERROR");
return 0;
}
int count = 1;
for(int i=1; i<strlen(argv[1]); i++){
if(isdigit(argv[1][i])!=0){
printf("%s","ERROR");
return 0;
}
//check if same as previous letter
if(prev==argv[1][i]){
count++;
}else{
//add letter and count to string
sprintf(temp, "%c%d", prev, count);
strcat(s, temp);
count = 1;
}
//update prev
prev=argv[1][i];
}
//add it to string
sprintf(temp, "%s%c%d", prev, count);
strcat(s, temp);
//check if result is smaller than input
if(strlen(s) > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
printf("%s\n", s);
}
free(s);
The advice in the comments and other answers are giving you good guidance on how manage the strings that you are dynamically allocating with malloc. But you can simplify your entire program without ever allocating a string and without using sprintf.
Consider this:
int lastChar = '\0';
int count = 0;
const char* arg = argv[1];
int isError = 0;
if (argc < 2) {
isError = 1;
}
while (*arg & !isError) { // scan argv[1] for digits
isError = isdigit(*arg);
arg++;
}
arg = argv[1]; // reset arg back to beginning of argv[1]
while (*arg && !isError) {
if (lastChar == *arg) {
count++;
}
else {
if (count > 0) {
printf("%c%d", lastChar, count);
}
lastChar = *arg;
count = 1;
}
arg++;
}
// print the last character being tracked or error message
if (isError) {
printf("ERROR");
}
else if (count > 0) {
printf("%c%d", lastChar, count);
}
printf("\n");

comparing a char to a string in C

I'm quite new to C and I'm wondering why in the code below, the char I'm comparing to each letter of the string word is showing that it's equal everytime.
For example
If I've inputted the word
apple
and I'm looking for any repeating char in "apple" my function. I pass in to the function each char of apple such as a, p, p etc. It should return 1 when I pass in p since it's repeated, but instead, for every char of apple, my function says a == word[0], a == word[1] even though word[1] for "apple" is 'p'.
I know char is ASCII, so each char has a number value, but I'm not sure why this is not working. Perhaps, I'm using the pointer *word in the functions arguments incorrectly?
My code is below for my function, rpt_letter:
int rpt_letter(char *word, char c)
{
int i;
int count = 0;
i = 0;
printf("This is the WORD %s\n", word);
while(count < 2)
{
if(word[i] == c)
{
count++;
printf("the count is %d\n the char is %c and the string is %c\n", count, c, word[i]);
}
i++;
}
if (count<2)
{
// printf("letter %c was not found in the array. \n", c);
return 0;
}
else
{
//printf("letter %c was found at index %d in the array.\n", c, mid);
repeats[rpt_counter] = c;
rpt_counter++;
return 1;
}
return 0;
}
I'll include the main method just in case -- but I believe the main method is working well
int main(void)
{
//! showArray(list, cursors=[ia, ib, mid])
//int n = 51;
char word[51];
scanf("%s", word);
//length of string
for (n=0; word[n] != '\0'; n++); //calculate length of String
printf("Length of the string: %i\n", n);
int count = 0;
//sort words
int i;
char swap = ' ';
for(int k = 0; k < n; k++)
{
for (i=0; i<n-1; i++)
{
//if prev char bigger then next char
if (word[i] > word[i+1])
{
//make swap = prev char
swap = word[i];
//switch prev char with next char
word[i] = word[i+1];
//make next letter char
word[i+1] = swap;
}
}
}
printf("%s\n", word);
for (i=0; i<n-1; i++)
{
int rpt = rpt_letter(word, word[i]);
if(rpt == 1)
{
count++;
}
}
printf("%d", count);
return 0;
}
I've tried a number of things such as using the operator !=, also <, > but it gives me the same result that each word[ia] == c.
You are getting this issue because in your code rpt_letter() the while loop has a terminating condition count >= 2. Now consider input apple and character a. As a appears in apple only once, the count after traversing the whole word remains 1. But the loop doesn't terminate. So, the index i becomes greater than the length of string and tries to check the character appearing after that.
The loop terminates eventually when it gets another a this way. You need to add a check for the terminating null character in your loop so that it doesn't cross the length of the string .
Change the while loop condition to something like -
while((count < 2) && (word[i] != '\0'))

array input wrong using strcpy

The code is supposed to take in as many string as the user wants to put in until they enter EOF. and it is doing that but after i try to ouput the code it comes out with these little half boxes instead of the string.
void sortString(char *s[], int count);
int main(){
int i;
char buff[BUFSIZ];
int count;
char** s = (char**)malloc(sizeof(char*));
//allows user to keep typing until EOF is reached.
printf("Here is the list of unsorted names: \n\n");
for (count = 0; fgets(buff, sizeof(buff), stdin); count++)
{
s[count] = malloc((sizeof(buff))*sizeof(char));//allocats memory at s[count].
strcpy(buff, s[count]);//adds the string in buff to s[count].
s = (char**) realloc(s, ((sizeof(s) + sizeof(buff)) * sizeof(char*)) + 1);//then reallocats memeory for s to take another string.
}
printf("\nCount is %d\n\n", count);
// Now sort string using sortString function
// Step 4: implement sortString function for the above-mentioned function declaration
for (i = 0; i < count; i++){
printf("%s \n",s[i]);
}
sortString(s, count);
printf("Here is the list of sorted names: \n\n");
for (i = 0; i < count; i++){
printf("%s",s[i]);
}
strcpy(buff, s[count]);//adds the string in buff to s[count].
No it doesn't. strcpy(dest, src), so it is copying s[count] (which is a buffer full of "random junk") to buff.

Passing a local static array to a function

I'm trying to pass a local array from a function letter_remover, which reads an original array, removes vowels + h, w and y, then copies that into a new array. This new array is then passed to main.
For example input plutonium would become pltnm. However when I call the function in main and print out the new array, it will duplicate some letters, for instance plltnm is printed.
void array_filler (char a[]);
char * letter_remover (char b[]);
int main (void)
{
char name[MAX];
char *p;
int i;
array_filler(name);
p = letter_remover(name);
printf("Local array passed back: ");
for (i = 0; i < MAX; i++)
{
printf("%s", p);
p++;
}
return 0;
}
If I print the new array created in the function letter_remover, it prints correctly. The letter_remover function creates the new array as a static char[] array and returns a char *
array_filler contains:
void array_filler (char a[])
{
printf("Type name: ");
int i = 0, c;
while ((c = getchar()) != '\n')
{
c = tolower(c);
if (isalpha(c))
{
a[i] = c;
i++;
}
}
a[i] = '\0';
printf("Name inside array: %s\n", a);
}
letter_remover contains:
char * letter_remover (char b[])
{
int i;
static char c[MAX];
char a[] = "aeiouywh";
printf("Name without forbidden characters: ");
for (i = 0; b[i] != '\0'; i++)
{
if (!strchr(a, b[i]))
{
c[i] = b[i];
printf("%c", c[i]);
}
}
c[i] = '\0';
printf("\n");
return c;
}
In main, you probably want to say
for (i = 0; i < MAX; i++)
{
printf("%c", p[i]);
p++;
}
In order to print each char in p. Since this will output beyond the 0 char, a better way would be to simply say printf("%s", p);, without a loop. Or just printf(p); if you trust the string! Or puts(p); which would apparently print a newline as well, which is most likely desirable for a terminal.
Your array index, into c, increases every time you go around the loop...instead you only need to change the index to c, when you actually copy a legal character.
for (j = 0, i = 0; b[i] != '\0'; i++)
{
if (!strchr(a, b[i]))
{
c[j] = b[i];
j++;
printf("%c", c[j]);
}
}
c[j] = '\0';
The main problem is here, in letter_remover:
for (i = 0; b[i] != '\0'; i++)
{
if (!strchr(a, b[i]))
{
c[i] = b[i];
printf("%c", c[i]);
}
}
c[i] = '\0';
You're using the same index for b and c. So at the end of the loop c contains NULL bytes at the spots where a letter is removed (because the array is static, it is initialized to all zeros). You need to use a separate index for c when you write to it:
for (i = 0, j = 0; b[i] != '\0'; i++)
{
if (!strchr(a, b[i]))
{
c[j] = b[i];
printf("%c", c[j]);
j++;
}
}
c[j] = '\0';
Then main where you're printing the result:
for (i = 0; i < MAX; i++)
{
printf("%s", p);
p++;
}
You're printing out the complete string repeatedly starting at each character. So the first time through it print "pl" before it hits a NULL bytes, the the next time it starts at the "l" and prints that again before it hits the NULL byte, and so on.
Once you apply the first fix, all you need to do is print it once:
printf("%s", p);

How to reset a char array to NULL (empty)

I am writing a code to rearrange the words in a string from back to front. I have first managed to arranged the characters from back to front but cannot seem to reset a string to null before swapping the second word in the string a second time and so on.
For example, with the input, "What the hell is going on here"
The output turns out to be, "here onre going ising hellg thelg Whatg"
So the last letters of the previous word stay with the "tempWord" variable. How can I fix this?
void revString(char statement[]);
int main (void){
int index;
char tempWord[LENGTH];
char statement[LENGTH] = "What the hell is going on here";
const char s[2] = " ";
char *word;
int wordCounter = 0;
revString(statement);
printf("%s\n", statement); //Temp printing
(Just so it's clear, the code I'm asking about is below this line)
//////////////////////////////////////////////////////////////////////////////////////
index = 0;
word = strtok(statement, s);
while (word != NULL){
wordCounter++;
for (index = 0; index <= strlen(word); index++){
tempWord[index] = '\0';
}
strcpy(tempWord, word);
revString(tempWord);
printf("%s ", tempWord);
word = strtok(NULL, s);
}
printf("\n");
printf("%d words", wordCounter);
}
Let me know what you think!
void revString(char original[]){
int index;
char temp[LENGTH];
int j = 1;
for (index = 0; index < strlen(original); index++, j++){
temp[(strlen(original) - j)] = original[index];
}
strcpy(original, temp);
original[strlen(original)] = '\0';
}
The problem is temp is not terminated with '\0'.
I modified the revString and tweaked a bit (called strlen only once)...
void revString(char original[]){
int index;
char temp[LENGTH];
int j = 1;
int len = strlen(original);
temp[len] = '\0';
for (index = 0; index < len; index++, j++){
temp[len - j] = original[index];
}
strcpy(original, temp);
original[len] = '\0';
}
Interestingly your original code doesn't give me a problem for LENGTH values from 30 to 100. For more than 200 bytes values it gives me strange characters (possibly the garbage) which got me into setting the last character in string "temp" to NULL.
Set the terminating Null character for tempword, according to the length of word
i.e.
while (word != NULL){
wordCounter++;
strcpy(tempWord, word);
revString(tempWord);
tempWord[strlen(word)] = '\0';
printf("%s ", tempWord);
word = strtok(NULL, s);
}
printf("\n");
printf("%d words", wordCounter);
}

Resources