2

I'm trying to read a file that contains a sequence of numbers

Example:

43917778700000762841090006653470575088202000
43919478100000762851090006653540575088203000
43919765400000815661090006653620575088204000

My code:

typedef struct rArc{
    long long int code;
}data;

int main(){
    long long int code,i=0;
    FILE *arc;
    data *v;
    v = NULL;

    arc = fopen("CODES.txt","r");
    while(fscanf(arc,"%lld",&code) != EOF){
        v = (data *)realloc(v,sizeof(data) * (i + 1));
        v[i].code = code;
        i++;
    }

    for(int j=0;j<i;j++){
        printf("%lld\n",v[j].code);
    }
}

But because the number is too big, it outputs some wierd random numbers. I was thinking in taking the last digit with modulo and adding into a vector, but because I cant even read it there's no way to do it the way i'm trying

Update

I've managed to read the file by changing the struct and main code variables to char code[45], I'm still working on how to do the maths but it was a start i guess

while(fscanf(arc,"%45s\n",&code) != EOF){
        v = (data *)realloc(v,sizeof(data) * (i + 1));
        v[i].code = code;
        i++;
    }

    for(int j=0;j<i;j++){
        printf("%45s\n",v[j].code);
    }
}
Zetto
  • 61
  • 5
  • 2
    What do you need to do with these numbers? – Eugene Sh. Jun 14 '18 at 17:12
  • Its a homework where I need to calculate the 10th,21st and 32st digit based on the previous numbers – Zetto Jun 14 '18 at 17:15
  • 2
    Then you don't need to read these as numbers. Just read digit by digit. – Eugene Sh. Jun 14 '18 at 17:18
  • So you have some long strings that happen to contain digits. Is there any particular reason to interpret these strings as decimal numbers? – n. m. could be an AI Jun 14 '18 at 17:19
  • 2
    One approach is to use `fgets` to read each line into a large buffer (e.g. 2K bytes). After [removing the newline](https://stackoverflow.com/questions/2693776), you can copy the string into a properly sized buffer obtained from `malloc`. Some implementations provide a `strdup` function that does the `malloc` and `strcpy` for you. – user3386109 Jun 14 '18 at 17:24
  • 3
    This homework, and those numbers, have been specifically designed to make the approach you started with impossible. Your instructor is trying to get you to think outside the box. (Even if you could manipulate these numbers as numbers, it would be unnecessarily difficult to inspect individual digits.) – Steve Summit Jun 14 '18 at 17:27
  • @n.m. I didn't thought about that, I was interpreting as decimals because I need to do math with them – Zetto Jun 14 '18 at 17:30
  • @SteveSummit I get it, I think I found a way to do it, if it works I'll post it here – Zetto Jun 14 '18 at 17:31
  • If you really need to do significant math on those numbers, you may need a multiprecision (or "arbitrary precision") arithmetic library such as GMP. – Steve Summit Jun 14 '18 at 17:51
  • What kind of math? You are saying "calculate 10th,21st and 32st digit" but this is vague and doesn't require any real calculations, just look at the digits, – n. m. could be an AI Jun 14 '18 at 18:08
  • Scan as a `double` and tolerate imprecision. – chux - Reinstate Monica Jun 14 '18 at 18:10
  • @n.m. The 0's in the file are a sort of "place holders" I need to do something like multiply 2-1-2... from right to left. E.g. 3x2 4x1 1x2 9x1 4x2 7x1 1x2 6x1 4x2 – Zetto Jun 14 '18 at 22:08
  • You are doing arithmetic with individual digits, not with long numbers. – n. m. could be an AI Jun 14 '18 at 22:14
  • @Zetto I'm still confused what you are asking? *"I need to calculate the 10th,21st and 32st digit based on the previous numbers"* How? `3x2 4x1 1x2 9x1 4x2 7x1 1x2 6x1 4x2` Where does that come from out of: `34194716400003108771090006638210572088201000`? So it's just 2x the 1st, 1x the 2nd; 2x the 3rd; 1x the 4th... – David C. Rankin Jun 14 '18 at 22:20
  • And what of the sequence at the 32nd character 1st line: `057...` the sum will not fit in the single `0`, so what then, overwrite the `57` as required? – David C. Rankin Jun 14 '18 at 22:25
  • For example, the code is 'devided' in 5 fields 34194.7164X 00031.08771Y 90006.63821Z 5 72088201000 I've changed the 0's to x,y,z for better understanding, to calculate the x for example, i need to multiply the numbers to his left as i said above then the sum of them will be the X value. But if a result of a any step is greater then 10 I need to get the modulo of the number by 10, e.g. 9x2 = 18%10 = 8 – Zetto Jun 14 '18 at 22:37

2 Answers2

1

Even after 3 iterations of clarification in the comments, I'm still not entirely clear on your algorithm, but I believe I understand it enough to help. From your responses to my comments, I understand you want to replace text at the 10th, 21st & 32nd characters with values arrived at by:

  1. summing all characters to the left of the position,

  2. the sum is produced by multiplying every other character by 2 starting by multiplying the 1st character by 2, the second by 1, the third by 2 and continuing with the 1-2-1-2-1... pattern of multiplying each digit until the wanted index is reached, and finally

  3. if any multiple by 2 exceeds 10, then you increase the sum by the product modulo 10 (e.g. sum = sum + (digit * 2-1-multiple) % 10) (or you may want to mod to total accumulated sum by 10 before each replacement at the 10th, 21st and 32nd characters -- that part is still unclear)

That being so, you can approach the problem by reading each string of digits into a fixed buffer. (do not skimp on buffer size). Once the line is read, iterate over the characters (validating each is a digit) keeping a running sum according to the pattern above until you reach the desired index. At the required index, replace the characters in the original string with the sum at that point, and continue until the final index and replacement at the 32nd character has been made.

To do that you can start by declaring your buffer to hold the file and opening the file (and validating it is open). You can take the filename to open as the 1st argument to your program or read from stdin if no argument is provided, e.g.

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

#define MAXC 512    /* constant for line-buffer size */

int main (int argc, char **argv) {

    char buf[MAXC] = "";    /* buffer to read each line */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

Next you will want to begin your read loop and declare the variables required to locate the desired positions to insert the sums, a way to keep track of your 2-1-2-1... multiplier sequence and your running sum. While not required here (you will only access through the 32nd character, it is a good idea to trim the trailing '\n' included in your buffer by fgets (or POSIX getline) as part of your validation that all characters fit in your buffer, e.g.

    while (fgets (buf, MAXC, fp)) {         /* read each line into buf */
        int const pos[] = { 10, 21, 32 },       /* indexes to replace */
            npos = sizeof pos / sizeof *pos;    /* no. of indexes */
        int ndx = 0,                            /* buffer index */
            *pdx = (int *)pos,                  /* pointer to pos */
            mult = 2;                           /* 2-1-2-... multiplier */
        size_t len = strlen (buf);              /* length of string */
        unsigned sum = 0;                       /* sum of digits */

        if (len && buf[len - 1] == '\n')    /* check for trailing '\n' */
            buf[--len] = 0;                 /* overwrite with nul-character */
        else if (len == MAXC - 1) {         /* otherwise string too long */
            fprintf (stderr, "error: line too long.\n");
            return 1;
        }

        printf ("original: %s\n", buf);     /* output the original string */

Once you have read your line and validated it fit, etc.. you need to loop over each character in the string performing your sum increment and replacement where required. You should also validate that each character read is a digit and not some stray alpha-character, or otherwise. By using a simple preprocessor #define passed as part of your compile string, you can provide optional debug output to help you sort out any problems with your algorithm, e.g.

        for (; buf[ndx]; ndx++) {           /* iterate over each character */
            if (!isdigit (buf[ndx])) {      /* validate character is digit */
                fprintf (stderr, "error: non-digit '%c'.\n", buf[ndx]);
                return 1;
            }
            sum += ((buf[ndx] - '0') * mult) % 10; /* increment sum by % 10 */
            if (ndx + 1 == *pdx) {          /* check if ndx+1 is position */
                int ndigit = 0;             /* no. of digits in sum */
                char tmp[MAXC] = "";        /* tmp buffer for sum as string */
                ndigit = sprintf (tmp, "%u", sum);  /* write sum to tmp */
#ifdef DEBUG    /* debug output */
                printf ("ndx+1: %2d, sum: %3u, ndigits: %d\n", 
                        ndx+1, sum, ndigit);
#endif
                if (ndigit) /* validate characters written to tmp */
                    memcpy (&buf[ndx], tmp, ndigit);    /* copy to buf */
                pdx++;              /* increment pos array index */
                if (*pdx == npos)   /* check if past last pos index */
                    break;
            }
            mult = (mult & 1) ? 2 : 1;      /* toggle mult 2-1-2-1... */
        }
        printf ("revised : %s\n\n", buf);   /* output updated number in buf */
    }

Putting it altogether, and adding the close of open file, you could do something like the following:

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

#define MAXC 512    /* constant for line-buffer size */

int main (int argc, char **argv) {

    char buf[MAXC] = "";    /* buffer to read each line */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {         /* read each line into buf */
        int const pos[] = { 10, 21, 32 },       /* indexes to replace */
            npos = sizeof pos / sizeof *pos;    /* no. of indexes */
        int ndx = 0,                            /* buffer index */
            *pdx = (int *)pos,                  /* pointer to pos */
            mult = 2;                           /* 2-1-2-... multiplier */
        size_t len = strlen (buf);              /* length of string */
        unsigned sum = 0;                       /* sum of digits */

        if (len && buf[len - 1] == '\n')    /* check for trailing '\n' */
            buf[--len] = 0;                 /* overwrite with nul-character */
        else if (len == MAXC - 1) {         /* otherwise string too long */
            fprintf (stderr, "error: line too long.\n");
            return 1;
        }

        printf ("original: %s\n", buf);     /* output the original string */

        for (; buf[ndx]; ndx++) {           /* iterate over each character */
            if (!isdigit (buf[ndx])) {      /* validate character is digit */
                fprintf (stderr, "error: non-digit '%c'.\n", buf[ndx]);
                return 1;
            }
            sum += ((buf[ndx] - '0') * mult) % 10; /* increment sum by % 10 */
            if (ndx + 1 == *pdx) {          /* check if ndx+1 is position */
                int ndigit = 0;             /* no. of digits in sum */
                char tmp[MAXC] = "";        /* tmp buffer for sum as string */
                ndigit = sprintf (tmp, "%u", sum);  /* write sum to tmp */
#ifdef DEBUG    /* debug output */
                printf ("ndx+1: %2d, sum: %3u, ndigits: %d\n", 
                        ndx+1, sum, ndigit);
#endif
                if (ndigit) /* validate characters written to tmp */
                    memcpy (&buf[ndx], tmp, ndigit);    /* copy to buf */
                pdx++;              /* increment pos array index */
                if (*pdx == npos)   /* check if past last pos index */
                    break;
            }
            mult = (mult & 1) ? 2 : 1;      /* toggle mult 2-1-2-1... */
        }
        printf ("revised : %s\n\n", buf);   /* output updated number in buf */
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

(note: the algorithm above includes the replaced values as part of the sum used at the next replacement index. i.e. your replacement at the 10th character is 52 for the first line. The digits 5 and 2 are used as part of the sum inserted at the 21st character)

Compile With DEBUG Defined (-DDEBUG)

$ gcc -Wall -Wextra -pedantic -std=c11 -Ofast -DDEBUG \
  -o bin/str_fill_sum_dbg str_fill_sum.c

(note: the '\' line-continuation is used above simply to keep the compile string from scrolling beyond the right margin of the web-page here. Also, I put all compiled executables in a bin subdirectory to keep my source directory clean, you can omit the bin/ portion of the executable name)

Example DEBUG Use/Output

The debug output shows the index, the current sum at that index which is inserted, and the number of characters replaced:

$ ./bin/str_fill_sum_dbg <dat/sumdigits.txt
original: 34194716400003108771090006638210572088201000
ndx+1: 10, sum:  52, ndigits: 2
ndx+1: 21, sum:  79, ndigits: 2
ndx+1: 32, sum: 109, ndigits: 3
revised : 34194716452003108771790006638211092088201000

original: 34193716400000921121090006638390572088201000
ndx+1: 10, sum:  50, ndigits: 2
ndx+1: 21, sum:  68, ndigits: 2
ndx+1: 32, sum: 104, ndigits: 3
revised : 34193716450000921121680006638391042088201000

original: 34191718400000607281090006638470572088201000
ndx+1: 10, sum:  48, ndigits: 2
ndx+1: 21, sum:  69, ndigits: 2
ndx+1: 32, sum: 103, ndigits: 3
revised : 34191718448000607281690006638471032088201000

original: 34195718400000550361090006638540572088201000
ndx+1: 10, sum:  46, ndigits: 2
ndx+1: 21, sum:  59, ndigits: 2
ndx+1: 32, sum:  98, ndigits: 2
revised : 34195718446000550361590006638549872088201000

original: 34192719900000550361090006638620572088201000
ndx+1: 10, sum:  51, ndigits: 2
ndx+1: 21, sum:  64, ndigits: 2
ndx+1: 32, sum:  95, ndigits: 2
revised : 34192719951000550361640006638629572088201000

original: 34198721400000550361090006638700572088201000
ndx+1: 10, sum:  47, ndigits: 2
ndx+1: 21, sum:  62, ndigits: 2
ndx+1: 32, sum:  88, ndigits: 2
revised : 34198721447000550361620006638708872088201000

Compile Normally

Simply drop the definition of the DEBUG define to omit the debug output, and out the executable in a separate filename if you like so both are available:

$ gcc -Wall -Wextra -pedantic -std=c11 -Ofast \
  -o bin/str_fill_sum str_fill_sum.c

Example Use/Output

$ ./bin/str_fill_sum <dat/sumdigits.txt
original: 34194716400003108771090006638210572088201000
revised : 34194716452003108771790006638211092088201000

original: 34193716400000921121090006638390572088201000
revised : 34193716450000921121680006638391042088201000

original: 34191718400000607281090006638470572088201000
revised : 34191718448000607281690006638471032088201000

original: 34195718400000550361090006638540572088201000
revised : 34195718446000550361590006638549872088201000

original: 34192719900000550361090006638620572088201000
revised : 34192719951000550361640006638629572088201000

original: 34198721400000550361090006638700572088201000
revised : 34198721447000550361620006638708872088201000

Look things over and let me know if you have further questions. If you algorithm is different than shown above, you should be able to easily incorporate any needed changes.

If modulo Of Total Before Insertion

If instead of taking modulo 10 of the result of each digit multiplied by 2, you instead want to just take the modulo of the sum before insertion, you could replace your character iteration loop with the following:

        for (; buf[ndx]; ndx++) {           /* iterate over each character */
            if (!isdigit (buf[ndx])) {      /* validate character is digit */
                fprintf (stderr, "error: non-digit '%c'.\n", buf[ndx]);
                return 1;
            }
            sum += ((buf[ndx] - '0') * mult); /* increment by digit*mult */
            if (ndx + 1 == *pdx) {          /* check if ndx+1 is position */
                int replace = sum % 10;
#ifdef DEBUG    /* debug output */
                printf ("ndx+1: %2d, sum: %3u, replace: %d\n", 
                        ndx+1, sum, replace);
#endif
                buf[ndx] = replace + '0';   /* replace char at buf[ndx] */
                pdx++;                      /* increment pos array index */
                if (*pdx == npos)           /* check if past last pos index */
                    break;
            }
            mult = (mult & 1) ? 2 : 1;      /* toggle mult 2-1-2-1... */
        }

Example DEBUG Use/Output

In that case the replacements of a single character would be as follows:

$ ./bin/str_fill_sum_dbg2 <dat/sumdigits.txt
original: 34194716400003108771090006638210572088201000
ndx+1: 10, sum:  52, replace: 2
ndx+1: 21, sum:  95, replace: 5
ndx+1: 32, sum: 145, replace: 5
revised : 34194716420003108771590006638215572088201000

original: 34193716400000921121090006638390572088201000
ndx+1: 10, sum:  50, replace: 0
ndx+1: 21, sum:  78, replace: 8
ndx+1: 32, sum: 145, replace: 5
revised : 34193716400000921121890006638395572088201000

original: 34191718400000607281090006638470572088201000
ndx+1: 10, sum:  48, replace: 8
ndx+1: 21, sum:  93, replace: 3
ndx+1: 32, sum: 157, replace: 7
revised : 34191718480000607281390006638477572088201000

original: 34195718400000550361090006638540572088201000
ndx+1: 10, sum:  56, replace: 6
ndx+1: 21, sum:  87, replace: 7
ndx+1: 32, sum: 146, replace: 6
revised : 34195718460000550361790006638546572088201000

original: 34192719900000550361090006638620572088201000
ndx+1: 10, sum:  61, replace: 1
ndx+1: 21, sum:  92, replace: 2
ndx+1: 32, sum: 148, replace: 8
revised : 34192719910000550361290006638628572088201000

original: 34198721400000550361090006638700572088201000
ndx+1: 10, sum:  57, replace: 7
ndx+1: 21, sum:  88, replace: 8
ndx+1: 32, sum: 141, replace: 1
revised : 34198721470000550361890006638701572088201000
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Just to clarify, for example a smaller code like 34191.0904X, X is calculated like 4x2=8, 0x1=0, 9x2=18, 0x1=0 and so on... then I sum up those results, that will be 40 (6+4+2+9+2+0+1+8+0+8) the 8 is in the place of where the 18 should be because it is greater then 10 as I tried to explain. Then the final value of X will be 10 - 40 % 10 = 10 – Zetto Jun 15 '18 at 01:33
  • I couldn't explain well enough the way the values are calculated, thats why the results you got is not exactly what was asked in the homework but now I know what to do and how to fix it, thanks alot! – Zetto Jun 15 '18 at 01:33
  • 1
    Sure, I looked at it several ways, but then concluded if it wasn't the exact algorithm, at least it gave you are proper framework to work with to tidy up the algorithm to fit your needs. Glad to help. Good luck with your class. – David C. Rankin Jun 15 '18 at 01:35
0
//This Program  will solve your problem. If you have any doubt ask me 

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


    int main()
    {

        int sum10th = 0 , sum21st = 0 , sum32nd = 0;    //to store the sum of 10th 21st 32nd

        FILE *stream;
        char *line = NULL;
        size_t len = 0;
        ssize_t nread;

        stream = fopen("number.txt","r");

        while ((nread = getline(&line, &len, stream)) != -1) 
        {
            if( nread >= 10)
            {

                sum10th += line[10 - 1] - 48 ;

                if( nread >= 21)
                {
                    sum21st += line[21 - 1] - 48;

                    if( nread >= 32)
                        sum32nd += line[32 - 1] - 48;
                }
            }
            strcpy(line," ");  //empty line
        }
        free(line);
        fclose(stream);
        printf("Sum at 10th 21st 32th is %d %d %d\n",sum10th , sum21st, sum32nd);

        return 0;
    }
    /*

    number.txt
    46546546546548614684654654651666
    65465455546868464654684797987987
    46865465465465465465654686468468

    */

    /*

    ouput
    Sum at 10th 21st 32th is 14 18 21

    */
  • 1
    Just a few nits. Don't hardcode numbers or strings. If you need constants `#define` them, if you need to pass a filename, use `argv[]`. When you open a file -- validate the file is open, don't use *magic numbers* `48` is ASCII `'0'` -- much more readable. `strcpy(line, " ");` does not `//empty line` it sets the first character to space, instead use `*line = 0;` to set the 1st character to the *nul-character*. I'm not convinced your algorithm is doing what the OP requires, but that is unclear in the question. Otherwise good use of POSIX `getline()`, and a bit more explanation would be nice. – David C. Rankin Jun 14 '18 at 19:16
  • 1
    It was my first answer. Thanks for you advice. I will try to improve it. – Rohit Kadam Jun 14 '18 at 19:27
  • 4
    yes, I know -- that's why I didn't ding you for it (your code shows good effort, it just needs more explaining). You want to avoid answers that provide just code and no explanation of what the code does -- more importantly, why you chose to code it the way you did. When you answer on SO, you step into the roll of teacher. You want to make sure you are a good one, and not one that leaves your student wondering "Why did the teacher do that?" (there are already too many of those kind of teachers...) – David C. Rankin Jun 14 '18 at 19:42
  • Ok. From now onwards I will try to explain my code properly as you done in above code. – Rohit Kadam Jun 15 '18 at 03:54
  • Sir, why you have use #ifdef DEBUG printf (&quot;ndx+1: %2d, sum: %3u, ndigits: %d\n&quot;, ndx+1, sum, ndigit); #endif In your above code – Rohit Kadam Jun 15 '18 at 03:56
  • That allows you to run the code between the `#ifdef DEBUG` (which is simply shorthand for `#if defined DEBUG`) by passing defining `DEBUG` on the command line at compile time. You can pass any define you want following the `-D` option. So if I want the program to output the `printf` between the `#ifdef DEBUG` and `#endif` all I need to do is pass `-DDEBUG` as part of my compile string. Example: `gcc -Wall -Wextra -DDEBUG -o myexename mysource.c`. If I don't want that code compile, I just omit the `-DDEBUG` and the compiler will not include it. – David C. Rankin Jun 15 '18 at 05:58