Okay ... You were pretty close
We just need to:
- add a loop that populates a buffer (e.g.
line
) with the correct number of zeros.
- add a
strcpy
from that buffer into the listOfNumbersReversed
array in the for
loop that you left blank.
- 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:
- It should not make a difference but ...
- 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
).
- The new version uses
ftell
and fseek
in place of rewind
so that the numbers are scanned once.
- I renamed
primNum
to mincount
and secNum
to numlen
to be more descriptive (I double checked the code as I did that).
- 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:
- Program works normally (the UB was, somehow, harmless)
- Program produces incorrect results
- 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;
}