2

Here I'm trying to create a function which accepts n number of integers and sum them together... But I'm having trouble having it print the correct ordinals. Am I using a wrong loop?

int i, count, sum, number;
sum = 0;
count = 0;


printf("Please indicate the number of integers:");
scanf("%d", &count);

for (i=0; i<count; i++){
    printf("Please input the %dst number:", i+1);
    scanf("%d", &number);

    sum = sum + number;
}

printf("sum is %d\n", sum);
return 0;

For example if i input count = 5, it will print

Please input the 1st number:
Please input the 2st number:
Please input the 3st number:
Please input the 4st number:
Please input the 5st number:
sum is 15

It prints the correct sum, but I want it to print the correct ordinal for every line.. for example, 2nd..3rd. Possibly without having to use an array

friedrojak
  • 57
  • 1
  • 13
  • What value did you give as input? – J...S Sep 10 '17 at 09:22
  • And what did `scanf()` return? – Andrew Henle Sep 10 '17 at 09:24
  • 2
    Possible duplicate of [Is there an easy way to create ordinals in C#?](https://stackoverflow.com/questions/20156/is-there-an-easy-way-to-create-ordinals-in-c) The answer is written in C#, but it should be trivial to port it to C. – vgru Sep 10 '17 at 09:34
  • 1
    Or a simply `char *ordinals[] = { "st", "nd", "rd", "th" };` and then simply use `number % place` to create the index to the correct ordinal. – David C. Rankin Sep 10 '17 at 09:39
  • @Groo : It is not a duplicate if the language is different (even if the C# solution could easily be adapted by someone familiar with both languages) - certainly not to warrant a close vote IMO. – Clifford Sep 10 '17 at 10:35

6 Answers6

2

In English, rules for ordinals are fairly simple (note: not "simple," but "fairly simple"):

  1. Below zero, you're on your own. Some might apply positive-number rules, others say it makes no sense to try a negative ordinal.

  2. Most ordinals end with 'th':

    • fourth
    • thirty-ninth
  3. Numbers ending with 1, 2, 3 are different:

    • first
    • twenty-second
    • one hundred eighty-third
  4. Except that numbers ending in 11, 12, 13 are 'th' numbers, because English treats the teens differently (six-teen vs. twenty-six). So:

    • eleventh
    • one hundred twelfth
    • thirteenth
  5. In general, only nerds think "zeroth" is funny. But it's still a -th, so it gets the default treatment.

In code:

if (n < 0) { /* Rule 1: good luck */ }

suffix = "th"; /* Rule 2: default = th */

if (1 <= n%10 && n%10 <= 3) { /* Rule 3: 1st, 2nd, 3rd */

    if (n%100 < 10 || n%100 > 20) { /* Rule 4: 11th-13th */
        suffix = (n%10 == 1) ? "st" 
               : (n%10 == 2) ? "nd" 
               :               "rd"
               ;
    }
}
aghast
  • 14,785
  • 3
  • 24
  • 56
  • In my test it generates `rd` suffix for all but 1st, 2nd, 101st, 102nd etc. – Clifford Sep 10 '17 at 10:03
  • Sounds like you reversed a condition or something. – aghast Sep 10 '17 at 10:09
  • My error - apologies; I copy and pasted your code into the `ordinal_suffix()` function from my answer, and returned `suffix`. However I made `suffix` static, and initialised it "th" where I should have _assigned_ it in every call. Works perfectly. – Clifford Sep 10 '17 at 10:30
1

This can be done by isolating the last decimal digit, so that for example 42 will be 42nd.The "teens" are special cases that need to be considered, such as 12th, not 12nd.

#include <stdio.h>

int main()
{
    int i, count, sum, number, order, teens;
    char *ordinal[] = {"st", "nd", "rd", "th" };
    sum = 0;
    count = 0;

    printf("Please indicate the number of integers: ");
    scanf("%d", &count);

    for (i = 0; i < count; i++) {
        teens = i % 100;
        order = i % 10;
        if(order > 3 || (teens >= 10 && teens < 20)) {
            order = 3;
        }
        printf("Please input the %d%s number: ", i+1, ordinal[order]);
        scanf("%d", &number);
        sum = sum + number;
    }
    printf("sum is %d\n", sum);
}

Please note that a "proper" program should be checking the return value from scanf.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
1

Here is a variation on using an array of ordinals and then a simply if and switch to handle all values (you can adjust to handle numbers > 100).

The routine is fairly straight forward. For everything (except values 10-13) follow the normal ordinal rules. So you simply set up a if block to handle the oddball values and then a switch with a mod of the value for the remainder, e.g.

Edit: - per request, you can add a check at the top of get_ordinal to scale values greater than 100 to their equivalent 0-99 range by successively subtracting 100 (and you can add more checks to optimize values greater than 1000, etc.), e.g.

#include <stdio.h>

char *get_ordinal (char **ordinals, int value)
{
    value %= 100;  /* normalize values between 0-100 */

    if (3 < value && value < 21)
        return ordinals[3];

    switch (value % 10) {
        case 1 :    return ordinals[0];
                    break;
        case 2 :    return ordinals[1];
                    break;
        case 3 :    return ordinals[2];
                    break;
        default:    return ordinals[3];
                    break;
    }
}

int main (void) {

    char *ordinals[] = { "st", "nd", "rd", "th" };

    for (int i = 1; i < 30; i++)
        printf ("Please enter the %d%s value:\n", 
                i, get_ordinal (ordinals, i));

    return 0;
}

Example Use/Output

$ ./bin/getordinals
Please enter the 1st value:
Please enter the 2nd value:
Please enter the 3rd value:
Please enter the 4th value:
Please enter the 5th value:
Please enter the 6th value:
Please enter the 7th value:
Please enter the 8th value:
Please enter the 9th value:
Please enter the 10th value:
Please enter the 11th value:
Please enter the 12th value:
Please enter the 13th value:
Please enter the 14th value:
Please enter the 15th value:
Please enter the 16th value:
Please enter the 17th value:
Please enter the 18th value:
Please enter the 19th value:
Please enter the 20th value:
Please enter the 21st value:
Please enter the 22nd value:
Please enter the 23rd value:
Please enter the 24th value:
Please enter the 25th value:
Please enter the 26th value:
Please enter the 27th value:
Please enter the 28th value:
Please enter the 29th value:

For values greater than 100, e.g.

$ ./bin/getordinals
Please enter the 90th value:
Please enter the 91st value:
Please enter the 92nd value:
Please enter the 93rd value:
Please enter the 94th value:
Please enter the 95th value:
Please enter the 96th value:
Please enter the 97th value:
Please enter the 98th value:
Please enter the 99th value:
Please enter the 100th value:
Please enter the 101st value:
Please enter the 102nd value:
Please enter the 103rd value:
Please enter the 104th value:
Please enter the 105th value:
Please enter the 106th value:
Please enter the 107th value:
Please enter the 108th value:
Please enter the 109th value:
Please enter the 110th value:
Please enter the 111th value:
Please enter the 112th value:
Please enter the 113th value:
Please enter the 114th value:
Please enter the 115th value:
Please enter the 116th value:
Please enter the 117th value:
Please enter the 118th value:
Please enter the 119th value:
Please enter the 120th value:
Please enter the 121st value:
Please enter the 122nd value:
Please enter the 123rd value:
Please enter the 124th value:
Please enter the 125th value:
Please enter the 126th value:
Please enter the 127th value:
Please enter the 128th value:
Please enter the 129th value:
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • What about 121st for example? Separating the `ordinals` array from `get_ordinal()` is not very cohesive design. Responsibility and knowledge of ordinals is split between `main()` and `get_ordinal()`. – Clifford Sep 10 '17 at 10:18
  • You just add a repeating division of 10 at the top of the function to scale whatever number you are sending to the function. e.g. `while (value > 100) value /= 10;` and then it will return the correct ordinals for any number you send it. – David C. Rankin Sep 10 '17 at 10:37
  • I know, so why not do that in your answer to make it more general? I was not asking how, but rather pointing out that this is not a _generalised_ answer. – Clifford Sep 10 '17 at 10:41
  • Ok, the while loop works but `n % 100` is much simpler and more efficient. – Clifford Sep 10 '17 at 10:52
0

Well you actually have to implement some more if-else conditions. You should:

for (i=0; i<count; i++){

if(i<100){

    if(i+1==11 || i+1==12 || i+1==13){
        printf("Please input the %dth number:", i+1);
        scanf("%d", &number);
    }
    else if((i+1)%10 == 1){
        printf("Please input the %dst number:", i+1);
        scanf("%d", &number);
    }
    else if((i+1)%10 == 2){
        printf("Please input the %dnd number:", i+1);
        scanf("%d", &number);
    }
    else if((i+1)%10 == 3){
        printf("Please input the %drd number:", i+1);
        scanf("%d", &number);
    }
    else{
        printf("Please input the %dth number:", i+1);
        scanf("%d", &number);
    }
}
sum = sum + number;
}
Kostas Ayfantop
  • 53
  • 1
  • 1
  • 10
0

It is complicated because there is not a direct mathematical relationship, because the ordinal suffixes are a result of natural language development rather than a consistent mathematical relationship.

Essentially all numbers are suffixed "th" unless the least significant digit is 1 to 3 and the number is not in the second decade of each centenary (i.e. the "teens"). That can be coded into a function that returns the appropriate suffix for any positive integer (negative ordinals do not really make much sense):

#include <stdio.h>

char* ordinal_suffix( int i )
{
    static const char* ord[] = { "st", "nd", "rd", "th" } ;
    int ordidx = 3 ;
    int imod100 = i % 100 ;
    if( imod100 < 11 || imod100 > 13 )
    {
        ordidx = (i % 10) - 1 ;
        if( ordidx > 3 || ordidx < 0 )
        {
            ordidx = 3 ;
        }
    }

    return ord[ordidx] ;
}

int main()
{
    for( int i = 1; i < 30; i++ )
    {
        printf( "%d%s\n", i, ordinal_suffix( i ) ) ;
    }

    for( int i = 99; i < 130; i++ )
    {
        printf( "%d%s\n", i, ordinal_suffix( i ) ) ;
    }
    return 0;
}

Output:

1st                                                                                                                                                                                           
2nd                                                                                                                                                                                           
3rd                                                                                                                                                                                           
4th                                                                                                                                                                                           
5th                                                                                                                                                                                           
6th                                                                                                                                                                                           
7th                                                                                                                                                                                           
8th                                                                                                                                                                                           
9th                                                                                                                                                                                           
10th                                                                                                                                                                                          
11th                                                                                                                                                                                          
12th                                                                                                                                                                                          
13th                                                                                                                                                                                          
14th                                                                                                                                                                                          
15th                                                                                                                                                                                          
16th                                                                                                                                                                                          
17th                                                                                                                                                                                          
18th                                                                                                                                                                                          
19th                                                                                                                                                                                          
20th                                                                                                                                                                                          
21st                                                                                                                                                                                          
22nd                                                                                                                                                                                          
23rd                                                                                                                                                                                          
24th                                                                                                                                                                                          
25th                                                                                                                                                                                          
26th                                                                                                                                                                                          
27th                                                                                                                                                                                          
28th                                                                                                                                                                                          
29th                                                                                                                                                                                          
99th                                                                                                                                                                                          
100th                                                                                                                                                                                         
101st                                                                                                                                                                                         
102nd                                                                                                                                                                                         
103rd                                                                                                                                                                                         
104th                                                                                                                                                                                         
105th                                                                                                                                                                                         
106th                                                                                                                                                                                         
107th                                                                                                                                                                                         
108th                                                                                                                                                                                         
109th                                                                                                                                                                                         
110th                                                                                                                                                                                         
111th                                                                                                                                                                                         
112th   
113th                                                                                                                                                                                         
114th                                                                                                                                                                                         
115th                                                                                                                                                                                         
116th                                                                                                                                                                                         
117th                                                                                                                                                                                         
118th                                                                                                                                                                                         
119th                                                                                                                                                                                         
120th                                                                                                                                                                                         
121st                                                                                                                                                                                         
122nd                                                                                                                                                                                         
123rd                                                                                                                                                                                         
124th                                                                                                                                                                                         
125th                                                                                                                                                                                         
126th                                                                                                                                                                                         
127th                                                                                                                                                                                         
128th                                                                                                                                                                                         
129th    
Clifford
  • 88,407
  • 13
  • 85
  • 165
-1

Please look if the following code can help you.

#include <stdio.h>
#include <memory.h>
char str[64];
char *AddOrdinal(int num) {

    sprintf(str, "%d", num);
    switch (num % 100) {
        case 11:
        case 12:
        case 13:
            strcat(str, "th ");
            return str;
    }

    switch (num % 10) {
        case 1:
            strcat(str, "st ");
            return str;
        case 2:
            strcat(str, "nd ");
            return str;
        case 3:
            strcat(str, "rd ");
            return str;
        default:
            strcat(str, "th ");
            return str;
    }

}

int main(void) {
    int i, count, sum, number;
    sum = 0;
    count = 0;
    printf("Please indicate the number of integers:");
    scanf("%d", &count);

    for (i = 0; i < count; i++) {
        printf("\nPlease input the %s number:", AddOrdinal(i + 1));
        scanf("%d", &number);

        sum = sum + number;
    }

    printf("\nsum is %d\n", sum);
    return 0;

}

Test

Please indicate the number of integers:3

Please input the 1st  number:2

Please input the 2nd  number:3

Please input the 3rd  number:4

sum is 9

Process finished with exit code 0
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
  • 1
    `AddOrdinal()` dangerously returns a pointer to a non-static local variable. `str[12]` is too short for longest 32 bit signed integer, and `int` may be larger that 32 bit in any case. Otherwise it works. – Clifford Sep 10 '17 at 10:14
  • This is a bad attempt of porting the [code from the C# answer](https://stackoverflow.com/a/20175/69809). Strings in C# are immutable, heap allocated, garbage collected objects. What this function is doing is returning a pointer to a stack based array, which goes out of scope after the function has returned. It's undefined behavior, so if this works on your computer, it works by accident. – vgru Sep 10 '17 at 13:42
  • @Clifford I tried to correct the code according to your comment. – Niklas Rosencrantz Sep 10 '17 at 22:28
  • @Groo Please look if you like my updated answer better. – Niklas Rosencrantz Sep 10 '17 at 22:29
  • 1
    Now it is not thread-safe, and uses a global (with an ill-advised name). – Clifford Sep 11 '17 at 06:47