Skip to main content
Typos
Source Link
SylvainD
  • 29.8k
  • 1
  • 49
  • 93
  • Because of the way you increment/update word_count and len, I had the feeling that we would always have the following property at the end of the loop : len == word_count + j. (I guess) you can prove/verify this using loop invariants. This is true just before j gets decremented and this is also true just after word_count gets incremented. In order to be 100%, I used the following macro : #define assert(c) if (!(c)) { printf ("" #c "' is not true!\n"); return 0; } and then I added assert(len == word_count+j); after incrementing word_count, after the k-look and at the end of the j-loop and the whole thing worked perfectly convincing me that my feeling was right.
    TL;DR : The conclusion of this is that we don't need the word_count variable if you replace len - word_count by j.

  • Because of the way j goes through the array, at the end of the j-loop, len is equal to the smallest index j leading to a space. Thus, we can easily decudededuce that for i in [0;len[, ch[i] is not a space. You can again verify this with the following assert : assert(ch[i]!=' ');.

  • At this stage, the code is slightly shortedshorter but still we have the same loop appearing twice : for(k = j+1; k < len; k++) printf(...) to print all the words but the last one and for(i = 0; i < len; i++) printf(...) to print the last word. Thus, my last trick was to make the j-loop go one step further (so that it reaches -1 which is pretty good because then your k-loop and your i-loop becomes equivalent as j+1==0) and print the last word. This comes at the cost of additional checks but it does work on your example.

     int main(void) {
     char ch[N], terminate;
     int len;
     printf("Enter a sentence: \n");
     for (int i = 0; i < N; i++) {
     ch[i] = getchar();
     if (ch[i] == '?' || ch[i] == '.' || ch[i] == '!' || ch[i] == '\n') {
         len = i;
         terminate = ch[i];
         break;
     }
     }
    
     for (int j = len - 1; j >= -1; j--) {
     if (j<0 || ch[j] == ' ') {
         for (int k = j+1; k < len; k++) {
         printf("%c",ch[k]);;
         }
         if (j>=0) {
         printf("%c",ch[j]);;
             len = j;
         }
     }
    
     }
     printf("%c\n", terminate);
    
     return 0;
     }
    
  • Because of the way you increment/update word_count and len, I had the feeling that we would always have the following property at the end of the loop : len == word_count + j. (I guess) you can prove/verify this using loop invariants. This is true just before j gets decremented and this is also true just after word_count gets incremented. In order to be 100%, I used the following macro : #define assert(c) if (!(c)) { printf ("" #c "' is not true!\n"); return 0; } and then I added assert(len == word_count+j); after incrementing word_count, after the k-look and at the end of the j-loop and the whole thing worked perfectly convincing me that my feeling was right.
    TL;DR : The conclusion of this is that we don't need the word_count variable if you replace len - word_count by j.

  • Because of the way j goes through the array, at the end of the j-loop, len is equal to the smallest index j leading to a space. Thus, we can easily decude that for i in [0;len[, ch[i] is not a space. You can again verify this with the following assert : assert(ch[i]!=' ');.

  • At this stage, the code is slightly shorted but still we have the same loop appearing twice : for(k = j+1; k < len; k++) printf(...) to print all the words but the last one and for(i = 0; i < len; i++) printf(...) to print the last word. Thus, my last trick was to make the j-loop go one step further (so that it reaches -1 which is pretty good because then your k-loop and your i-loop becomes equivalent as j+1==0) and print the last word. This comes at the cost of additional checks but it does work on your example.

     int main(void) {
     char ch[N], terminate;
     int len;
     printf("Enter a sentence: \n");
     for (int i = 0; i < N; i++) {
     ch[i] = getchar();
     if (ch[i] == '?' || ch[i] == '.' || ch[i] == '!' || ch[i] == '\n') {
         len = i;
         terminate = ch[i];
         break;
     }
     }
    
     for (int j = len - 1; j >= -1; j--) {
     if (j<0 || ch[j] == ' ') {
         for (int k = j+1; k < len; k++) {
         printf("%c",ch[k]);;
         }
         if (j>=0) {
         printf("%c",ch[j]);;
             len = j;
         }
     }
    
     }
     printf("%c\n", terminate);
    
     return 0;
     }
    
  • Because of the way you increment/update word_count and len, I had the feeling that we would always have the following property at the end of the loop : len == word_count + j. (I guess) you can prove/verify this using loop invariants. This is true just before j gets decremented and this is also true just after word_count gets incremented. In order to be 100%, I used the following macro : #define assert(c) if (!(c)) { printf ("" #c "' is not true!\n"); return 0; } and then I added assert(len == word_count+j); after incrementing word_count, after the k-look and at the end of the j-loop and the whole thing worked perfectly convincing me that my feeling was right.
    TL;DR : The conclusion of this is that we don't need the word_count variable if you replace len - word_count by j.

  • Because of the way j goes through the array, at the end of the j-loop, len is equal to the smallest index j leading to a space. Thus, we can easily deduce that for i in [0;len[, ch[i] is not a space. You can again verify this with the following assert : assert(ch[i]!=' ');.

  • At this stage, the code is slightly shorter but still we have the same loop appearing twice : for(k = j+1; k < len; k++) printf(...) to print all the words but the last one and for(i = 0; i < len; i++) printf(...) to print the last word. Thus, my last trick was to make the j-loop go one step further (so that it reaches -1 which is pretty good because then your k-loop and your i-loop becomes equivalent as j+1==0) and print the last word. This comes at the cost of additional checks but it does work on your example.

     int main(void) {
     char ch[N], terminate;
     int len;
     printf("Enter a sentence: \n");
     for (int i = 0; i < N; i++) {
     ch[i] = getchar();
     if (ch[i] == '?' || ch[i] == '.' || ch[i] == '!' || ch[i] == '\n') {
         len = i;
         terminate = ch[i];
         break;
     }
     }
    
     for (int j = len - 1; j >= -1; j--) {
     if (j<0 || ch[j] == ' ') {
         for (int k = j+1; k < len; k++) {
         printf("%c",ch[k]);;
         }
         if (j>=0) {
         printf("%c",ch[j]);;
             len = j;
         }
     }
    
     }
     printf("%c\n", terminate);
    
     return 0;
     }
    
Source Link
SylvainD
  • 29.8k
  • 1
  • 49
  • 93

I'm not quite sure if you are aiming only for smaller length or also for better code/readability. Depending on the answer, you can take the following style comments into account (which are somehow pretty personal except for the last one):

  • In C code, I find it easier to have bigger indentations
  • I prefer having a whitespace after keywords such as for and if.
  • It's usually recommended to define variables in the smallest possible scope. In your case, if you compile with the -std=c99 flag or equivalent, you could define your variables containing indexes at the beginning of your for loops.

This being said, three things I found :

  • Because of the way you increment/update word_count and len, I had the feeling that we would always have the following property at the end of the loop : len == word_count + j. (I guess) you can prove/verify this using loop invariants. This is true just before j gets decremented and this is also true just after word_count gets incremented. In order to be 100%, I used the following macro : #define assert(c) if (!(c)) { printf ("" #c "' is not true!\n"); return 0; } and then I added assert(len == word_count+j); after incrementing word_count, after the k-look and at the end of the j-loop and the whole thing worked perfectly convincing me that my feeling was right.
    TL;DR : The conclusion of this is that we don't need the word_count variable if you replace len - word_count by j.

  • Because of the way j goes through the array, at the end of the j-loop, len is equal to the smallest index j leading to a space. Thus, we can easily decude that for i in [0;len[, ch[i] is not a space. You can again verify this with the following assert : assert(ch[i]!=' ');.

  • At this stage, the code is slightly shorted but still we have the same loop appearing twice : for(k = j+1; k < len; k++) printf(...) to print all the words but the last one and for(i = 0; i < len; i++) printf(...) to print the last word. Thus, my last trick was to make the j-loop go one step further (so that it reaches -1 which is pretty good because then your k-loop and your i-loop becomes equivalent as j+1==0) and print the last word. This comes at the cost of additional checks but it does work on your example.

     int main(void) {
     char ch[N], terminate;
     int len;
     printf("Enter a sentence: \n");
     for (int i = 0; i < N; i++) {
     ch[i] = getchar();
     if (ch[i] == '?' || ch[i] == '.' || ch[i] == '!' || ch[i] == '\n') {
         len = i;
         terminate = ch[i];
         break;
     }
     }
    
     for (int j = len - 1; j >= -1; j--) {
     if (j<0 || ch[j] == ' ') {
         for (int k = j+1; k < len; k++) {
         printf("%c",ch[k]);;
         }
         if (j>=0) {
         printf("%c",ch[j]);;
             len = j;
         }
     }
    
     }
     printf("%c\n", terminate);
    
     return 0;
     }