1

I am trying to pass a C string (char*) to a function lower(char *) (as in the prototype) that returns a C string char *lower() to main(). But I am not getting the desired output. Point out my mistakes and suggest some techniques for getting the result.

(Note : <string.h> functions are not allowed & the task must be done with pointers). Here is my code,

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

char *lower(char *);

void main() {
    char pass[10], *pass1;

    printf("Enter a password\n");
    scanf("%s", pass);

    pass1 = lower(pass);

    printf("Lower case  ");

    int i = 0;
    while (*pass1 != '\0') {
        printf("%c", *(pass1 + i));
        i++;
    } 
}

char *lower(char *p) {
    while (*p != '\0') {
        if (*p >= 'A' && *p <= 'Z') {
            *p = *p + 32;
        }
        p++;
    }
    return p;
}
13
  • 4
    At the end of the loop, p points to the end of the string, and you're returning that pointer. Commented Jul 13, 2017 at 19:46
  • 1
    You should be using a different variable to iterate through the string, so you can return the original pointer. Commented Jul 13, 2017 at 19:47
  • 3
    You should use isupper() and tolower() to test case and convert case, rather than hard-coding 32 as the difference. Commented Jul 13, 2017 at 19:48
  • 4
    Since the function modifies the string in place, why do you need to return a pointer? Commented Jul 13, 2017 at 19:49
  • 4
    Why are you printing the string with a loop instead of using printf("%s", pass1)? Commented Jul 13, 2017 at 19:50

2 Answers 2

5

There are multiple problems in your code:

  • main should have the prototype int main(void) a for good style have a return 0; statement at the end of the body.

  • scanf() should protect the destination array from overflow by specifying the maximum number of characters to read into it: scanf("%9s", pass); and you should check its return value for successful conversion.

  • you should use pass1[i] instead of *(pass1 + i). Both expressions are equivalent but the first is more readable. Incidentally, another equivalent but surprising alternative is i[pass1], don't use it unless you want to confuse the reader, which might be advisable in a password handling routine.

  • printing individual characters with printf("%c", pass1[i]) does not seem mandated by the rules posted: use a single printf statement.

  • Furthermore, the loop test is constant: while (*pass1 != '\0') as you only increment i in the loop. Hence an infinite loop and undefined behavior when you access elements of pass beyond its end.

  • as you pass the return value to printf(), function lower() should return the original pointer, not the pointer to the end of the argument string.

  • you should not hard-code the difference between lowercase and uppercase characters, 32 only works for ASCII, not EBCDIC. *p += 'a' - 'A'; would be both more portable and more readable. It works for both ASCII and EBCDIC, but might not for other less common character sets and the test if (*p >= 'A' && *p <= 'Z') is not precise enough for EBCDIC as the uppercase letters do not form a contiguous set. Use the macros from <ctype.h> for a portable solution.

Here is a corrected version:

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

char *lower(char *);

int main(void) {
    char pass[80];

    printf("Enter a password\n");
    if (scanf("%79s", pass) == 1) {
        printf("Lower case: %s\n", lower(pass));
    }
    return 0;
}

char *lower(char *s) {
    for (char *p = s; *p != '\0'; p++) {
        *p = tolower((unsigned char)*p);
    }
    return s;
}

If you cannot use <ctype.h>, use this less portable version:

char *lower(char *s) {
    for (char *p = s; *p != '\0'; p++) {
        if (*p >= 'A' && *p <= 'Z')
            *p += 'a' - 'A';
    }
    return s;
}
Sign up to request clarification or add additional context in comments.

Comments

3
char *lower(char *p){
    char *ptr = p;
    while(*p != '\0'){
        if( *p>='A' && *p<='Z' ){
        *p = *p + 32;
        }
        p++;
    }
    return ptr;
}

why sometimes is good to return something like converted char pointer - to use it in other operations - for example as a parameter in another function call.

6 Comments

because OP wanted. Why strcpy returns dest? Silly question - because you can use it instantly as a parameter in another function call. - parse(lower(s)); @KevinDTimm 12k reputation and you ask such a ridiculous questions?
The only change I would make to your answer would be to add a brief explanation why returning the modified p is a logic error. It's in the comments above but it would make the answer better.
It always helps to explain the problem in addition to posting corrected code. They might just copy-paste without learning anything.
Ok sorry. So it was just the coincidence. Actually it is strange question if asked by the experienced programmer.
Brainfart - mea culpa
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.