tamir
tamir

Reputation: 29

Printf for string goes down a line unwillingly

This is my program (school exercise, should be receiving a string from the user, change it and return the original and new string in a certain format):

#include <stdio.h>
#define MAX_STRING_LENGTH 50

char switchChar(char c) {
    if ((c >= 'A') && (c <= 'Z')) {
        c = c + 32;
    } else
    if ((c >= 'a') && (c <= 'z')) {
        c = c - 32;
    }
    if ((c > '5') && (c <= '9')) {
        c = 56;
    }
    if ((c >= '0') && (c < '5')) {
        c = 48;
    }
    return c;
}

int main(void) {    
    char temp;
    int i = 0;

    char stringInput[MAX_STRING_LENGTH + 1];
    printf("Please enter a valid string\n");
    fgets(stringInput, 50, stdin);
    char newString[MAX_STRING_LENGTH + 1];

    while ((i != MAX_STRING_LENGTH + 1) && (stringInput[i] != '\0')) {
        temp = switchChar(stringInput[j]);
        newString[i] = temp;
        i++;
    }
    printf(  "\"%s\"", stringInput);
    printf("->");
    printf(  "\"%s\"", newString);

    return 0;
}

When running, the output goes down a line after the string and before the last " character, although it should all be printed in the same line.

I would appreciate any directions.

Upvotes: 1

Views: 317

Answers (3)

chqrlie
chqrlie

Reputation: 144540

There are several issues in your code:

  • fgets() reads and leaves the newline character at the end of the destination array if present and if enough space is available. For consistency with your algorithm, you should strip this newline. You can do this safely with stringInput[strcspn(stringInput, "\n")] = '\0'; or use a little more code if you cannot use <string.h>. The presence of this newline character explains the observed undesirable behavior.

  • You read a line with fgets(), but you pass a buffer size that might be incorrect: hard coded to 50 when the array size is MAX_STRING_LENGTH + 1. With MAX_STRING_LENGTH defined as 50, it is not a problem, but if you later change the definition of the macro, you might forget to update the size argument to fgets(). Use sizeof stringInput for consistency

  • you forget to set the null terminator in newString. Testing the boundary value for i is not necessary as stringInput is null terminated within the array boundaries.

  • in switchChar(), you should not hardcode character values from the ASCII charset: it reduces portability and most importantly, reduces readability.

Here is a corrected and simplified version:

#include <stdio.h>

#define MAX_STRING_LENGTH  50

char switchChar(char c) {
    if ((c >= 'A') && (c <= 'Z')) {
        c = c + ('a' - 'A');
    } else
    if ((c >= 'a') && (c <= 'z')) {
        c = c - ('a' - 'A');
    } else
    if ((c > '5') && (c <= '9')) {
        c = '8';
    } else
    if ((c >= '0') && (c < '5')) {
        c = '0';
    }
    return c;
}

int main(void) {    
    char stringInput[MAX_STRING_LENGTH + 1];
    char newString[MAX_STRING_LENGTH + 1];
    int c;

    printf("Please enter a valid string\n");

    if (fgets(stringInput, sizeof stringInput, stdin) != NULL) {
        // strip the newline character if present
        //stringInput[strcspn(stringInput, "\n")] = '\0';
        char *p;
        for (p = stringInput; *p != '\0' && *p != '\n'); p++)
            continue;
        *p = '\0';

        for (i = 0; stringInput[i] != '\0'; i++) {
            newString[i] = switchChar(stringInput[i]);
        }
        newString[i] = '\0';

        printf("\"%s\"", stringInput);
        printf("->");
        printf("\"%s\"", newString);
        printf("\n");
    }
    return 0;
}

Upvotes: 3

Serge Ballesta
Serge Ballesta

Reputation: 148870

You requirements contain:

  • get only one string
  • no special processing for blank characters

In that case, scanf is probably more adapted than fgets, because the former will clean the input for any initial blank(space or tab) and stop before the first trailing blank (space, tab, cr or newline). Remark: as scanf stops before the first blank, the string cannot contains spaces or tab. If it is a problem, use fgets.

Just replace the line:

fgets(stringInput, 50, stdin);

with:

i = scanf("%50s", stringInput);
if (i != 1) {   /* always control input function return code */
     perror("Could not get input string");
     return 1;
}

If you prefere to use fgets for any reason, you should remove the (optional) trailing newline:

if (NULL == fgets(stringInput, 50, stdin)) { /* control input */
     perror("Could not get input string");
     return 1;
}
int l = strlen(stringInput);
if ((l > 0) && (stringInput[l - 1] == '\n')) { /* test for a trailing newline */
    stringInput[l - 1] = '\0';                 /* remove it if found */
}

Upvotes: 0

P.P
P.P

Reputation: 121347

It's because fgets() reads in the newline character as well if there's room in the buffer and it's stored in your newString.

You can remove it with:

 fgets(stringInput,50,stdin);
 stringInput[strcspn(stringInput, "\n")]  = 0; /* removes the trailing newline if any */

From fgets():

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the
buffer. A terminating null byte ('\0') is stored after the last character in the buffer.

Upvotes: 1

Related Questions