简体   繁体   中英

Swap occurrences of two most frequent letters in a string

I don't know what is the problem in my code, but when I compile I get:

warning: passing arg 2 of `strcspn' makes pointer from integer without a cast

Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define STR_LEN 50

int main(void) {
    int i = 0, j = 0, length = 0, count1 = 0, count2 = 0, count3 = 0;
    char letter3 = 'a', letter2 = 'a', string[STR_LEN] = { 0 };

    length = strlen(string);
    printf("Enter a sentence: ");
    fgets(string, STR_LEN, stdin);

    for (i = 0; i < length; i++) {
        for (j = 0; j < length; j++) {
            if (string[i] == string[j]) {
                count1++;
            } else {
                count1 = 0;
            }
        }
        if (count1 > count3) {
            count2 = count3;
            count3 = count1;
            letter2 = letter3;
            letter3 = string[i];
        } else
        if (count1 > count2) {
            count2 = count1;
            letter2 = string[i];
        }
    }

    string[strcspn(string, letter2)] = letter3;
    string[strcspn(string, letter3)] = letter2;

    printf("\n %s", string);

    system("pause");

    return 0;
}

The code supposed to get a sentence from the user and switch the most common letter in the sentence with the 2nd common letter.

The immediate problem

The strcspn() function takes two strings as arguments, but you're passing a string and a character. You need to convert the character into a string somehow. One way to do that would be:

int sep[2] = "";
sep[0] = letter2;
string[strcspn(string, sep)] = letter3;
sep[0] = letter3;
string[strcspn(string, sep)] = letter2;

However, the first call changes the first occurrence of letter2 to letter3 ; the second call changes the first occurrence of letter3 (which might be the one just replaced in the previous call) with letter2 . This is not a complete job of transforming the strings — you need to scan the whole string making the changes.

Implementing a solution

One possibility is this:

#include <ctype.h>
#include <stdio.h>
#include <string.h>

#define NULL_VALUE '\0'

static inline void map(char *str, int len, int c_old, int c_new)
{
    for (int i = 0; i < len; i++)
    {
        if (str[i] == c_old)
            str[i] = c_new;
    }
}

int main(void)
{
    char buffer[4096];

    printf("Enter a sentence: ");
    if (fgets(buffer, sizeof(buffer), stdin) == 0)
        return 0;
    int length = strlen(buffer);
    if (length > 0)
        buffer[--length] = '\0';

    putchar('\n');
    printf("Original [%s]\n", buffer);

    int count[256] = { 0 };
    for (int i = 0; i < length; i++)
    {
        if (isalpha((unsigned char)buffer[i]))
            count[(unsigned char)buffer[i]]++;
    }

    int max1_count = 0;
    int max2_count = 0;
    char max1_value = '\0';
    char max2_value = '\0';
    for (int i = 0; i < 256; i++)
    {
        if (count[i] > max1_count)
        {
            max2_count = max1_count;
            max2_value = max1_value;
            max1_count = count[i];
            max1_value = i;
        }
        else if (count[i] > max2_count)
        {
            max2_count = count[i];
            max2_value = i;
        }
    }

    /*
    ** Since a string is a sequence of non-null character codes followed
    ** by a null byte, it is safe to use '\0' as the temporary value in
    ** the three-step swap operation
    */
    if (max2_count > 0)
    {
        map(buffer, length, max1_value, NULL_VALUE);
        map(buffer, length, max2_value, max1_value);
        map(buffer, length, NULL_VALUE, max2_value);
    }

    printf("Revised  [%s]\n", buffer);

    return 0;
}

The only reason for using the macro NULL_VALUE is so that the symmetry of the three map() lines is self-evident.

Example runs

I called the program ccswap19 , and I used Bash 'here strings' to supply the data — the putchar('\\n'); means that the output appears on a separate line from the prompt. There'd be a blank line before the 'Original' printing if you ran the program interactively.

$ ccswap19 <<< "The hidden costs of the exodus are now revealed for all to see."
Enter a sentence: 
Original [The hidden costs of the exodus are now revealed for all to see.]
Revised  [Tho hiddon cests ef tho oxedus aro new rovoalod fer all te soo.]
$ ccswap19 <<< "aaaaaaaaaaaa"
Enter a sentence: 
Original [aaaaaaaaaaaa]
Revised  [aaaaaaaaaaaa]
$ ccswap19 <<< "aaaabaaaaaaa"
Enter a sentence: 
Original [aaaabaaaaaaa]
Revised  [bbbbabbbbbbb]
$

strcspn(const char *str1, const char *str2) looks for the first instance of any characters in the second string in the first string. You are passing a character instead of a string as the second argument. You want the function strchr(const char *string, int character), which looks for a single character.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM