2

I need help on my code. I have done a code (below) to read the numbers from a .txt file. The first two numbers are put on a int variable, the numbers from the second line onwards are on an array of strings. Then created another string with its content reversed.Ps: second number is the size of the strings in the array.
My problem is that, if the first number is higher than the number of strings in the array, it's suppose to fill the array with a number of strings of 0's(of the size of the second number), until the number of strings on the array is the same of the first number. If the first number is equal or lower than the number of strings in the array, do not insert anything else, and just leave the string as it is.
I'll put an exemple bellow.

Input

7 8
10101011
10000011
11111111
11111111

Output

List of Numbers on Array:
10101011
10000011
11111111
11111111

List of Numbers Reversed on Array:
11111111
11111111
10000011
10101011

List of Numbers Reversed on Array after Inserting the rest:
11111111
11111111
10000011
10101011
00000000
00000000
00000000
int main() {
    FILE *file = fopen("file.txt", "r");
    if (file == NULL) {
        fprintf(stderr, "Cannot open file.txt: %s\n", strerror(errno));
        return 1;
    }
    // read the 2 numbers
    int primNum, secNum;
    if (fscanf(file, "%d %d\n", &primNum, &secNum) != 2) {
        fprintf(stderr, "invalid file format\n");
        fclose(file);
        return 1;
    }
    // count the number of items that can be read
    char line[100];
    int counter;
    for (counter = 0; fscanf(file, "%99s", line) == 1; counter++)
         continue;

    printf("Total number of items: %d\n", counter);

    // Rewind and re-read the contents into the array
    rewind(file);


    char listOfNumbers[100][100];
    int i;
    if (fscanf(file, "%d %d\n", &primNum, &secNum) != 2) {
        fprintf(stderr, "cannot reread the numbers\n");
        fclose(file);
        return 1;
    }
    for (i = 0; i < counter; i++) {
        if (fscanf(file, "%99s", listOfNumbers[i]) != 1) {
            // Cannot read all the numbers file changed ?
            printf("could only read %d numbers out of %d\n", i, counter);
            counter = i;
            break;
        }
    }
    fclose(file);

    // Testing Results
    printf("1st Number: %d\n", primNum);
    printf("2nd Number: %d\n\n", secNum);
    printf("List of Numbers on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbers[i]);
    }
    //Reversing the array of strings
    char listOfNumbersReversed[counter][secNum+1];
    int j = 0;
    for(i = counter - 1; i >=0 ; i--){
        memcpy(&listOfNumbersReversed[j][0], &listOfNumbers[i][0], secNum+1);
        j++;
    }

    //Testing Results
    printf("\n\nList of Numbers Reversed on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }
    //Adding the extra strings of 0's
    if(counter < primNum){     
        //Using the example from above, in this part, it's supposed to add 0's in the form of string inside: listOfNumbersReversed[4], listOfNumbersReversed[5], listOfNumbersReversed[6].
        for(i=i; i < primNum; i++){
            //Using the example from above, this part is supposed to add 0's in the string until its the same size of the secNum, the string will be '00000000'.
        }
    }
    //Testing Results
    printf("\n\nFinal List of Numbers Reversed:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }

    return 0;
}

How can i add a limited number of '0's inside a selected place of a string. I've tried but can't seem to solve this problem(line 62 of the code), but i'cant seem to? Sorry for any grammar error or if my question is confusing.

  • For primNum=7, it's the min number of numbers/strings needed. But, for secNum=8, is this the _width_ of the individual numbers/strings? That is, you add `00000000`. If secNum=5, would you add `00000` instead? – Craig Estey Jul 11 '22 at 18:46
  • @CraigEstey, yes, secNum is the number of zeros that is needed to be added in the string. In that case, if secNum=5, you would add 00000. – LearningLinux Jul 11 '22 at 18:49

1 Answers1

1

Okay ... You were pretty close

We just need to:

  1. add a loop that populates a buffer (e.g. line) with the correct number of zeros.
  2. add a strcpy from that buffer into the listOfNumbersReversed array in the for loop that you left blank.
  3. set counter to primNum

Here's the refactored code:

Edit: I've updated the code so the input is no longer hardwired to file.txt. That is now the default, but now you can do (e.g.): ./program other.txt

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

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

    char *arg;
    if (argc >= 2)
        arg = argv[1];
    else
        arg = "file.txt";

    FILE *file = fopen(arg, "r");
    if (file == NULL) {
        fprintf(stderr, "Cannot open %s: %s\n", arg, strerror(errno));
        return 1;
    }

    // read the 2 numbers
    int primNum, secNum;

    if (fscanf(file, "%d %d\n", &primNum, &secNum) != 2) {
        fprintf(stderr, "invalid file format\n");
        fclose(file);
        return 1;
    }

    // count the number of items that can be read
    char line[100];
    int counter;

    for (counter = 0; fscanf(file, "%99s", line) == 1; counter++)
        continue;

    printf("Total number of items: %d\n", counter);

    // Rewind and re-read the contents into the array
    rewind(file);

    char listOfNumbers[100][100];
    int i;

    if (fscanf(file, "%d %d\n", &primNum, &secNum) != 2) {
        fprintf(stderr, "cannot reread the numbers\n");
        fclose(file);
        return 1;
    }
    for (i = 0; i < counter; i++) {
        if (fscanf(file, "%99s", listOfNumbers[i]) != 1) {
            // Cannot read all the numbers file changed ?
            printf("could only read %d numbers out of %d\n", i, counter);
            counter = i;
            break;
        }
    }
    fclose(file);

    // Testing Results
    printf("1st Number: %d\n", primNum);
    printf("2nd Number: %d\n\n", secNum);
    printf("List of Numbers on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbers[i]);
    }
    // Reversing the array of strings
    char listOfNumbersReversed[counter][secNum + 1];
    int j = 0;

    for (i = counter - 1; i >= 0; i--) {
        memcpy(&listOfNumbersReversed[j][0], &listOfNumbers[i][0], secNum + 1);
        j++;
    }

    // Testing Results
    printf("\n\nList of Numbers Reversed on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }

    // Adding the extra strings of 0's
    if (counter < primNum) {
        // Using the example from above, in this part, it's supposed to
        // add 0's in the form of string inside:
        // listOfNumbersReversed[4],
        // listOfNumbersReversed[5],
        // listOfNumbersReversed[6].

#if 1
        // create buffer with correct number of zeros
        for (i = 0;  i < secNum;  ++i)
            line[i] = '0';
        line[i] = 0;
#endif

#if 0
        for (i = i; i < primNum; i++) {
#else
        for (i = counter; i < primNum; i++) {
#endif
            // Using the example from above, this part is supposed to add 0's
            // in the string until its the same size of the secNum, the string
            // will be '00000000'.
#if 1
            strcpy(listOfNumbersReversed[i],line);
#endif
        }

#if 1
        // extend the number of lines to output
        counter = primNum;
#endif
    }

    // Testing Results
    printf("\n\nFinal List of Numbers Reversed:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }

    return 0;
}

In the above code, I used cpp conditionals to denote old vs. new code:

#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif

Note: this can be cleaned up by running the file through unifdef -k:

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

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

    char *arg;
    if (argc >= 2)
        arg = argv[1];
    else
        arg = "file.txt";

    FILE *file = fopen(arg, "r");
    if (file == NULL) {
        fprintf(stderr, "Cannot open %s: %s\n", arg, strerror(errno));
        return 1;
    }

    // read the 2 numbers
    int primNum, secNum;

    if (fscanf(file, "%d %d\n", &primNum, &secNum) != 2) {
        fprintf(stderr, "invalid file format\n");
        fclose(file);
        return 1;
    }

    // count the number of items that can be read
    char line[100];
    int counter;

    for (counter = 0; fscanf(file, "%99s", line) == 1; counter++)
        continue;

    printf("Total number of items: %d\n", counter);

    // Rewind and re-read the contents into the array
    rewind(file);

    char listOfNumbers[100][100];
    int i;

    if (fscanf(file, "%d %d\n", &primNum, &secNum) != 2) {
        fprintf(stderr, "cannot reread the numbers\n");
        fclose(file);
        return 1;
    }
    for (i = 0; i < counter; i++) {
        if (fscanf(file, "%99s", listOfNumbers[i]) != 1) {
            // Cannot read all the numbers file changed ?
            printf("could only read %d numbers out of %d\n", i, counter);
            counter = i;
            break;
        }
    }
    fclose(file);

    // Testing Results
    printf("1st Number: %d\n", primNum);
    printf("2nd Number: %d\n\n", secNum);
    printf("List of Numbers on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbers[i]);
    }
    // Reversing the array of strings
    char listOfNumbersReversed[counter][secNum + 1];
    int j = 0;

    for (i = counter - 1; i >= 0; i--) {
        memcpy(&listOfNumbersReversed[j][0], &listOfNumbers[i][0], secNum + 1);
        j++;
    }

    // Testing Results
    printf("\n\nList of Numbers Reversed on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }

    // Adding the extra strings of 0's
    if (counter < primNum) {
        // Using the example from above, in this part, it's supposed to
        // add 0's in the form of string inside:
        // listOfNumbersReversed[4],
        // listOfNumbersReversed[5],
        // listOfNumbersReversed[6].

        // create buffer with correct number of zeros
        for (i = 0;  i < secNum;  ++i)
            line[i] = '0';
        line[i] = 0;

        for (i = counter; i < primNum; i++) {
            // Using the example from above, this part is supposed to add 0's
            // in the string until its the same size of the secNum, the string
            // will be '00000000'.
            strcpy(listOfNumbersReversed[i],line);
        }

        // extend the number of lines to output
        counter = primNum;
    }

    // Testing Results
    printf("\n\nFinal List of Numbers Reversed:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }

    return 0;
}

Here is the program output:

Total number of items: 4
1st Number: 7
2nd Number: 8

List of Numbers on Array:
10101011
10000011
11111111
11111111

List of Numbers Reversed on Array:
11111111
11111111
10000011
10101011

Final List of Numbers Reversed:
11111111
11111111
10000011
10101011
00000000
00000000
00000000

UPDATE:

I've tried to run the code with the example that i gave,and at the end of the output it returns: Final List of Numbers Reversed: 11111111 and no other string. Just that one. – LearningLinux

The first time i tested it worked fine, the output was the one expected, but since i ran the code a second time, i hasn't worked. – LearningLinux

Ran the code again, with the same input, and the output for the last printf was = Final List of Numbers Reversed: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 – LearningLinux

Hmm ... I'd check the input file to ensure that it's not been corrupted somehow.

I've updated the program to allow the input file to be passed as the first arg (with no args, it defaults to original behavior and uses file.txt).

That way, you can create multiple tests in different files (e.g test1.txt, test2.txt, ...) and don't have to edit the file to change the test data (which can be error prone).

I've run the program a number of times here, with the same and different input files and they all work as expected (see below). Thus, I'm unable to reproduce your current behavior on my system.

I've created a slightly more cleaned up version:

  1. It should not make a difference but ...
  2. I didn't like the fact that the two numbers (line count and number width) on the first line were being reread (after the rewind).
  3. The new version uses ftell and fseek in place of rewind so that the numbers are scanned once.
  4. I renamed primNum to mincount and secNum to numlen to be more descriptive (I double checked the code as I did that).
  5. The original code (using rewind) can be used if the program is compiled with -DREWIND

Here is that code:

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

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

    char *arg;
    if (argc >= 2)
        arg = argv[1];
    else
        arg = "file.txt";

    FILE *file = fopen(arg, "r");
    if (file == NULL) {
        fprintf(stderr, "Cannot open %s: %s\n", arg, strerror(errno));
        return 1;
    }

    // read the 2 numbers
    int mincount, numlen;

    if (fscanf(file, "%d %d\n", &mincount, &numlen) != 2) {
        fprintf(stderr, "invalid file format\n");
        fclose(file);
        return 1;
    }

    // remember starting position of number list
#ifndef REWIND
    long pos = ftell(file);
#endif

    // count the number of items that can be read
    char line[100];
    int counter;

    for (counter = 0; fscanf(file, "%99s", line) == 1; counter++)
        continue;

    printf("Total number of items: %d\n", counter);

    // Rewind and re-read the contents into the array
#ifdef REWIND
    rewind(file);
#endif

    char listOfNumbers[100][100];
    int i;

#ifdef REWIND
    if (fscanf(file, "%d %d\n", &mincount, &numlen) != 2) {
        fprintf(stderr, "cannot reread the numbers\n");
        fclose(file);
        return 1;
    }
#else
    fseek(file, pos, 0);
#endif

    for (i = 0; i < counter; i++) {
        if (fscanf(file, "%99s", listOfNumbers[i]) != 1) {
            // Cannot read all the numbers file changed ?
            printf("could only read %d numbers out of %d\n", i, counter);
            counter = i;
            break;
        }
    }
    fclose(file);

    // Testing Results
    printf("1st Number: %d\n", mincount);
    printf("2nd Number: %d\n\n", numlen);

    printf("List of Numbers on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbers[i]);
    }

    // Reversing the array of strings
    char listOfNumbersReversed[counter][numlen + 1];
    int j = 0;

    for (i = counter - 1; i >= 0; i--) {
        memcpy(&listOfNumbersReversed[j][0], &listOfNumbers[i][0], numlen + 1);
        j++;
    }

    // Testing Results
    printf("\n\nList of Numbers Reversed on Array:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }

    // Adding the extra strings of 0's
    if (counter < mincount) {
        // Using the example from above, in this part, it's supposed to
        // add 0's in the form of string inside:
        // listOfNumbersReversed[4],
        // listOfNumbersReversed[5],
        // listOfNumbersReversed[6].

#if 1
        // create buffer with correct number of zeros
        for (i = 0;  i < numlen;  ++i)
            line[i] = '0';
        line[i] = 0;
#endif

#if 0
        for (i = i; i < mincount; i++) {
#else
        for (i = counter; i < mincount; i++) {
#endif
            // Using the example from above, this part is supposed to add 0's
            // in the string until its the same size of the numlen, the string
            // will be '00000000'.
#if 1
            strcpy(listOfNumbersReversed[i],line);
#endif
        }

#if 1
        // extend the number of lines to output
        counter = mincount;
#endif
    }

    // Testing Results
    printf("\n\nFinal List of Numbers Reversed:\n");
    for (i = 0; i < counter; i++) {
        printf("%s\n", listOfNumbersReversed[i]);
    }

    return 0;
}

Here are some more tests I ran ...

Input:

9 4
1010
1000
1111
1110

Output:

Total number of items: 4
1st Number: 9
2nd Number: 4

List of Numbers on Array:
1010
1000
1111
1110

List of Numbers Reversed on Array:
1110
1111
1000
1010

Final List of Numbers Reversed:
1110
1111
1000
1010
0000
0000
0000
0000
0000

Input:

Total number of items: 4
1st Number: 4
2nd Number: 8

List of Numbers on Array:
10101011
10000011
11111111
11110000

List of Numbers Reversed on Array:
11110000
11111111
10000011
10101011

Final List of Numbers Reversed:
11110000
11111111
10000011
10101011

Input:

9 8
10101011
10000011
11111111
11110000

Output:

Total number of items: 4
1st Number: 9
2nd Number: 8

List of Numbers on Array:
10101011
10000011
11111111
11110000

List of Numbers Reversed on Array:
11110000
11111111
10000011
10101011

Final List of Numbers Reversed:
11110000
11111111
10000011
10101011
00000000
00000000
00000000
00000000
00000000

UPDATE #2:

The issue is the definition of listOfNumbersReversed:

char listOfNumbersReversed[counter][numlen + 1];

Before reading further, you may wish to examine this and [try to] fix this yourself.

I really don't know what is happening. I've tried to compile the new version of the code and it also didnt work. The first test with the example i gave returned the same thing again. The first test you did returned: Final List of Numbers Reversed: 1110 1110 1110 1110 1110 1110 1110 1110 1110 (all repeated). And the second test you did, won't even print anything on the final list. I've tried to execute it in CodeBlocks and recreated the project in Eclipse. Both have returned the same results. – LearningLinux

The clue [for me] is in the "all repeated". See below.

Just used an online compiler (onlinegdb.com) and it worked normally. Its so weird. No idea why it won't work on my IDEs – LearningLinux

When a program works differently on various systems, this is an indication of UB (undefined behavior): Undefined, unspecified and implementation-defined behavior

My apologies ... I should have caught this before.

UB can cause:

  1. Program works normally (the UB was, somehow, harmless)
  2. Program produces incorrect results
  3. Program segfaults / aborts

On my system [and the online system you tried], we always got (1). On your system, we got (2)

Although UB can be caused by just about anything, the "usual suspect" is writing beyond the end of an array. When 1110 was repeated 9 times, that was the tipoff. It could only occur with UB in the extension for loop.

The root cause is the definition of listOfNumbersReversed:

char listOfNumbersReversed[counter][numlen + 1];

If mincount (nee primNum) is greater than counter, there is not enough space in the array to hold the extension numbers.

The fix:

int revcount = (mincount > counter) ? mincount : counter;
char listOfNumbersReversed[revcount][numlen + 1];

In fact, compiling the original code with: -fsanitize=address would have flagged the issue at runtime.

Here is a further cleaned up version:

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

#define MAXNUM          100             // maximum number of numbers
#define MAXLEN          100             // maximum width of a number

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

    char *arg;
    if (argc >= 2)
        arg = argv[1];
    else
        arg = "file.txt";

    FILE *file = fopen(arg, "r");
    if (file == NULL) {
        fprintf(stderr, "Cannot open %s: %s\n", arg, strerror(errno));
        return 1;
    }

    // read the 2 numbers
    int mincount, numlen;

    if (fscanf(file, "%d %d\n", &mincount, &numlen) != 2) {
        fprintf(stderr, "invalid file format\n");
        fclose(file);
        return 1;
    }

    // remember starting position of number list
    long pos = ftell(file);

    char line[MAXLEN];

    // don't "hardwire" the format -- use one that is guaranteed to match
#if 1
    char fmt[10];
    sprintf(fmt,"%%%ds",MAXLEN - 1);
#endif

    // count the number of items that can be read
    int counter;
    for (counter = 0; fscanf(file, fmt, line) == 1; counter++)
        continue;

    printf("Total number of items: %d\n", counter);

#if 0
    char listOfNumbers[100][100];
#else
    char listOfNumbers[MAXNUM][MAXLEN];
#endif
    int i;

    // go to start of numbers in the file
    fseek(file, pos, 0);

    // Testing Results
    printf("1st Number: %d\n", mincount);
    printf("2nd Number: %d\n\n", numlen);

    for (i = 0; i < counter; i++) {
#if 1
        char *cp = listOfNumbers[i];
#endif

        if (fscanf(file, fmt, cp) != 1) {
            // Cannot read all the numbers file changed ?
            printf("could only read %d numbers out of %d\n", i, counter);
            counter = i;
            break;
        }

// NOTE/FIX: additional check on width of number is necessary due to how
// listOfNumbersReversed is defined
#if 1
        size_t curlen = strlen(cp);
        if (curlen > numlen) {
            printf("number is too long: curlen=%zu numlen=%zu %s\n",
                curlen,numlen,cp);
            counter = i;
            return 1;
        }
#endif
    }
    fclose(file);

    printf("List of Numbers on Array:\n");
    for (i = 0; i < counter; i++)
        printf("%s\n", listOfNumbers[i]);

    // Reversing the array of strings
// NOTE/BUG: if mincount > counter, this is too short to contain the extension
// elements and is UB
#if 0
    char listOfNumbersReversed[counter][numlen + 1];
#else
    int revcount = (mincount > counter) ? mincount : counter;
    char listOfNumbersReversed[revcount][numlen + 1];
#endif

    int j = 0;
    for (i = counter - 1; i >= 0; i--) {
#if 0
        memcpy(&listOfNumbersReversed[j][0], &listOfNumbers[i][0], numlen + 1);
#else
        strcpy(&listOfNumbersReversed[j][0], &listOfNumbers[i][0]);
#endif
        j++;
    }

    // Testing Results
    printf("\n\nList of Numbers Reversed on Array:\n");
    for (i = 0; i < counter; i++)
        printf("%s\n", listOfNumbersReversed[i]);

    // Adding the extra strings of 0's
    if (counter < mincount) {
        // Using the example from above, in this part, it's supposed to
        // add 0's in the form of string inside:
        // listOfNumbersReversed[4],
        // listOfNumbersReversed[5],
        // listOfNumbersReversed[6].

        // create buffer with correct number of zeros
        for (i = 0;  i < numlen;  ++i)
            line[i] = '0';
        line[i] = 0;

        for (i = counter; i < mincount; i++) {
            // Using the example from above, this part is supposed to add 0's
            // in the string until its the same size of the numlen, the string
            // will be '00000000'.
            strcpy(listOfNumbersReversed[i],line);
        }

        // extend the number of lines to output
        counter = mincount;
    }

    // Testing Results
    printf("\n\nFinal List of Numbers Reversed:\n");
    for (i = 0; i < counter; i++)
        printf("%s\n", listOfNumbersReversed[i]);

    return 0;
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • I've tried to run the code with the example that i gave,and at the end of the output it returns: Final List of Numbers Reversed: 11111111 and no other string. Just that one. – LearningLinux Jul 12 '22 at 02:45
  • The first time i tested it worked fine, the output was the one expected, but since i ran the code a second time, i hasn't worked. – LearningLinux Jul 12 '22 at 02:52
  • Ran the code again, with the same input, and the output for the last printf was = Final List of Numbers Reversed: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 – LearningLinux Jul 12 '22 at 02:59
  • @LearningLinux I've done an update to my answer ... – Craig Estey Jul 12 '22 at 04:06
  • I really don't know what is happening. I've tried to compile the new version of the code and it also didnt work. The first test with the example i gave returned the same thing again. The first test you did returned: Final List of Numbers Reversed: 1110 1110 1110 1110 1110 1110 1110 1110 1110 (all repeated). And the second test you did, won't even print anything on the final list. I've tried to execute it in CodeBlocks and recreated the project in Eclipse. Both have returned the same results. – LearningLinux Jul 12 '22 at 05:45
  • Just used an online compiler (https://www.onlinegdb.com) and it worked normally. Its so weird. No idea why it won't work on my IDEs – LearningLinux Jul 12 '22 at 06:44
  • 1
    @LearningLinux Had the Aha! moment -- see update #2 – Craig Estey Jul 12 '22 at 15:08
  • Tested it all again with the new code and the problem was finally solved, thank you so much!! – LearningLinux Jul 12 '22 at 17:28