char函数应该在C中返回什么?

时间:2018-03-25 17:15:13

标签: c function pointers char scanf

我想知道char函数应该返回什么?

以此代码为例:

#include <stdio.h>

char *convert(char *str);

int main() {

    char *str[1000];
    printf("Enter a string: ");
    scanf("%[^\n]s", str);
    printf("\nOutput: %s\n", str);
    convert(str);
    printf("\nAfter converting to lowercase: %s\n\n", str);

    return 0;
}

char *convert(char *str) {

    int i = 0;
    char *p;
    char *c;

    while (str[i] != '\0') {
        if (str[i] >= 'A' && str[i] <= 'Z') {
            str[i] = str[i] + 32;
        }
        i++;
    }

    for (p = c = str; *p != '\0'; p++) {
        *c = *p;
        if (*c < '0' || *c > '9') {
            c++;
        }
    }
    *c = '\0';

    return str;
}

我在char * convert函数中返回 str ,但即使我没有返回任何内容或返回0,此代码也能正常工作。我应该将此函数更改为void吗?这段代码好吗?

1 个答案:

答案 0 :(得分:1)

Should I change this function to void? Is this code alright?

You always want to match the return type of the function to how your function is intended to be used. There is nothing wrong returning char * from convert. Since you do not alter the address of str within convert, that provides the option of using the return as a parameter to another function, such as:

printf("\nAfter converting to lowercase: %s\n\n", convert (str));

If you had declared convert as void, that would no longer be an option. However, by returning str, you also lose the ability to change where str points within the function. (so for example in converting to lowercase, you couldn't simply increment str++ in your function) Not a limitation, just something to be aware of. Really, either way is fine.

As for your convert function itself, it does not compress the spaces on either side of the digits it removes in str. For example, if you enter the string:

My dog HAS 23 Fleas

as input, you receive:

my dog has  fleas

as output with the double-space (on from either side of 23 still present in the string. You can clean that up by adding a flag tracking consecutive spaces or by adding additional tests.

The final comment I would have would be to refactor your convert into two functions, one to convert to lowercase (say str2lower) and one to remove digits (say strrmdigits). The allows you to reuse the functions independently. There are many times you will want to convert to lowercase, and maybe a few you want to remove digits, but there will be very few times you want to both convert to lowercase and remove the digits from a string. So think ahead when factoring your code.

A splitting of your convert into a str2lower and strrmdigits could go something like follows:

char *str2lower (char *str)  /* convert string to lower case */
{
    for (char *p = str; *p; p++)
        if ('A' <= *p && *p <= 'Z')
            *p ^= ('A' ^ 'a');    /* works for ASCII & EBCDIC */

    return str;
}

The function to remove digits while compressing surrounding whitespace into one, could look like:

char *strrmdigits (char *str)   /* remove included digits */
{
    char *p = str;      /* pointer used to elminate digits */
    int nspace = 0;     /* flag tracking consequtive spaces */

    for (int i = 0; str[i]; i++)    /* loop over each char */
        if (str[i] < '0' || '9' < str[i]) { /* digit? */
            if (str[i] != ' ') {    /* if not a space */
                *p++ = str[i];      /* write character */
                nspace = 0;         /* set space count 0 */
            }   /* otherwise */
            else if (!nspace) {     /* no space written yet? */
                *p++ = str[i];      /* write space */
                nspace = 1;         /* set space written flag */
            }
        }

    *p = 0;     /* nul-terminate at p */

    return str;
}

You could then tidy up your test program a bit by removing the magic number 1000 and using a proper #define to define the needed constant. (don't use magic numbers in your code). While fgets is a better choice for user input (you simply trim the trailing '\n'), if you are going to use scanf, then you must always validate the return, and when reading strings into an array, always protect your array bounds by including a proper field width modifier to specify the maximum number of characters to read. (there is no way around it, you cannot use a variable, so the field width is a value you have to hardcode.)

With those tweaks included, you could do something like the following (making use of the return from each of the functions), e.g.

#include <stdio.h>

#define MAXC 1000   /* if you need a constant, #define one (or more) */

char *str2lower (char *str);
char *strrmdigits (char *str);

int main (void) {

    char str[MAXC] = "";                /* initialize all strings zero */

    printf ("Enter a string: ");
    if (scanf ("%999[^\n]s", str) != 1) {   /* always validate return */
        fputs ("error: invalid input.\n", stderr);
        return 1;
    }
    printf ("\nOutput: '%s'\n\n", str);

    printf ("to lowercase  : '%s'\n\n", str2lower (str));
    printf ("digits removed: '%s'\n", strrmdigits (str));

    return 0;
}

Example Use/Output

$ ./bin/charrtn
Enter a string: My dog HAS 23 Fleas

Output: 'My dog HAS 23 Fleas'

to lowercase  : 'my dog has 23 fleas'

digits removed: 'my dog has fleas'

Look things over and let me know if you have further questions.