Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A program that prints even and odd characters from a string

Tags:

arrays

c

string

This is for Homework

I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.

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

int main(void) {
    char *str[41];
    char odd[21];
    char even[21];
    int i = 0; 
    int j = 0;
    int k = 0;

    printf("Enter a string (40 characters maximum): ");
    scanf("%s", &str);

    while (&str[i] < 41) {
        if (i % 2 == 0) {
            odd[j++] = *str[i];
        } else {
            even[k++] = *str[i];
        }
        i++;
    }

    printf("The even string is:%s\n ", even);
    printf("The odd string is:%s\n ", odd);

    return 0;
}

When I try and compile my program I get two warnings:

  1. For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.

  2. On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.

When I compile the program, I get random characters for both the even and odd string.

Any help would be appreciated!

like image 223
chrisHG Avatar asked Nov 13 '17 19:11

chrisHG


3 Answers

this declaration is wrong:

char *str[41];

you're declaring 41 uninitialized strings. You want:

char str[41];

then, scanf("%40s" , str);, no & and limit the input size (safety)

then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)

while (str[i]) {
    if (i % 2 == 0) {
        odd[j++] = str[i];
    } else {
        even[k++] = str[i];
    }
    i++;
}

if you want to use a pointer (assignement requirement), just define str as before:

char str[41];

scan the input value on it as indicated above, then point on it:

char *p = str;

And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:

while (*p) { // test end of string termination
    if (i % 2 == 0) {  // if ((p-str) % 2 == 0) { would allow to get rid of i
        odd[j++] = *p;
    } else {
        even[k++] = *p;
    }
    p++;
    i++;
}

(we have to increase i for the even/odd test, or we would have to test p-str evenness)

aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:

even[k] = odd[j] = '\0';

(as another answer states, check the concept of even & odd, the expected result may be the other way round)

like image 180
Jean-François Fabre Avatar answered Nov 05 '22 05:11

Jean-François Fabre


There are multiple problems in your code:

  • You define an array of pointers char *str[41], not an array of char.
  • You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
  • You should limit the number of characters read by scanf.
  • You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
  • You should read the characters from str with str[i].
  • You should null terminate the even and odd arrays.

Here is a modified version:

#include <stdio.h>

int main(void) {
    char str[41];
    char odd[21];
    char even[21];
    int i = 0; 
    int j = 0;
    int k = 0;

    printf("Enter a string (40 characters maximum): ");
    if (scanf("%40s", str) != 1)
        return 1;

    while (str[i] != '\0') {
        if (i % 2 == 0) {
            odd[j++] = str[i];
        } else {
            even[k++] = str[i];
        }
        i++;
    }
    odd[j] = even[k] = '\0';

    printf("The even string is: %s\n", even);
    printf("The odd string is: %s\n", odd);

    return 0;
}

Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.

like image 3
chqrlie Avatar answered Nov 05 '22 06:11

chqrlie


Many answers all ready point out the original code`s problems.

Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.

As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.

Alternative print: If code used "%.*s", the array does not need a null character termination.

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

int main(void) {
  char str[41];

  printf("Enter a string (40 characters maximum): ");
  fflush(stdout);
  if (scanf("%40s", str) == 1) {
    int i;
    printf("The even string is:");
    for (i = 0; str[i]; i++) {
      if (i % 2 == 0) {
        str[i / 2] = str[i];  // copy character to an earlier part of `str[]`
      } else {
        putchar(str[i]);
      }
    }
    printf("\n");
    printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
  }
  return 0;
}

or simply

printf("The even string is:");
for (int i = 0; str[i]; i++) {
  if (i % 2 != 0) {
    putchar(str[i]);
  }
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
  if (i % 2 == 0) {
    putchar(str[i]);
  }
}
printf("\n");
like image 2
chux - Reinstate Monica Avatar answered Nov 05 '22 06:11

chux - Reinstate Monica