Problem: successful build but program displays nonsense in output (programmed in C not C++)

This is my first semester doing any kind of programming whatsoever and I have a series of functions to write for an assignment.
I've written this function to read information in a text file and display it on-screen. The build is successful but the output shows "[|[|[|[|" shown repeatedly for countless lines in the command window and then it displays the information in the file but the 2 integer arrays show numbers such as "3471188" and "3441420". The numbers change each time I run the program. Also, It doesn't display the first block of each of the first 4 arrays. In other words it doesn't display the first 4 column headings. I've included the text below my code.
Please help me resolve this issue.

Here is the code:

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

int main ()
{
char omonth [930][12], oday[930][10], oactvty[930][30];
int odate[930][5] = {0};
int oreps[930][8] = {0};

FILE *Ptr;

Ptr = fopen("test text.txt", "r");
if (Ptr == NULL)
{
printf("Cannot open file\n");
exit(0);
}

while (!feof(Ptr))
{
fscanf(Ptr, "%s %d %s %s %d", omonth, &odate, oday, oactvty, &oreps);
printf("%s \t %d \t %s \t %s \t %d \n", omonth, odate, oday, oactvty, oreps);
}

fclose(Ptr);
return 0;
}



The text file it is supposed to copy looks like this:


Month Date Day Activity Repetitions
January 1 Monday brushed_teeth 9
January 1 Monday combed_hair 5
January 1 Monday stepped_up_bottom_step 20
January 1 Monday cleaned_basin 40
January 2 Tuesday brushed_teeth 10
January 2 Tuesday combed_hair 10
January 2 Tuesday stepped_up_bottom_step 10
January 2 Tuesday cleaned_basin 20

The preview shows the text with only 1 space between each but in reality tabs are used to evenly space into columns.

Thanks in advance.

P.S. I know absolutely no C++ code and we aren't allowed to use it in the assignment. I also use Microsoft Visual C++ 2008 Express Edition with SP1 to write and build my programs.
Last edited on
I am not able to understand the exact requirement . please elobrate.
printf("%s \t %d \t %s \t %s \t %d \n", omonth, odate, oday, oactvty, oreps);

None of those variables are chars or ints. All of them are pointers. Consider this:
int myInts[100][100];

myInts[1][1] is an integer.
myInts[1] is a pointer to (the first integer of) an array of integers.
myInts is a pointer to (the first pointer of) an array of pointers to (the first integer of) arrays of integers.

The "nonsense" output you're getting are addresses.

@bluecoder
The requirements of this function are that it is supposed to read the contents of the text file and store them in variables to be used later in the program and eventually the same information must be printed on the screen.
The source code must be in C and and it all the files and solutions must be compatible with Visual C++ 2008

@Gaminic
I declared all of my variables in the beginning. I'm not sure I understand what you're saying either because from what you've said I would say that line of code should do what I want which is display the contents of those variables with tabs between them. The program seems to be doing that except it displays large numbers in the 2 integer columns. Each integer column has its own number that it prints all the way down.
omonth is a pointer to a pointer to a char. %s indicates it is to be interpreted as a pointer to a char. They're not the same thing.

Similarly odate, oday, oactvty, and oreps.
Last edited on
@moschops
I understand that but that's the only way I know how to do it and it has worked every time without a problem until now. I wrote similar code last Thursday and it worked then as well. I essentially copied the code and changed the arrays to suit the file format and size.
It worked every time until you changed an apple into an orange. Suddenly you aren't getting any apple juice.

When you use the printf() function (and other like functions), you must make sure that the type of each argument matches the format specifier (that "%n" thing).

To print a string, you must use "%s", and the argument must be a char*
To print an integer, you must use "%d", and the argument must be an int.
Etc.

You are trying to use "%s" to print a string, but your argument is a char** (a pointer to a pointer to a character).
You are trying to use "%d" to print an integer, but your argument is a int**.
Etc.

The same caveats hold true with scanf().

So, to print a specific month, for example, use printf( "%s", omonth[ 3 ] ); (I would presume this prints something like "April".)

To be fair, using the C formatted I/O routines is confusing, because it is not straightforward.


Here are some hints:

1
2
3
/* read a string */
char s[ 100 ];
scanf( "%99s", s );
1
2
3
/* read an integer */
int n;
scanf( "%d", &n );

When dealing with arrays, you need to remember to dereference the item in the array.

1
2
3
/* read a string into the second element of an array of five strings */
char s[ 5 ][ 100 ];
scanf( "%99s", s[ 1 ] );
1
2
3
/* read an integer into the fifth element of an array of five integers */
int n[ 5 ];
scanf( "%d", &(n[ 4 ]) );

Hope this helps.
@Duoas
Thanks, I think I understand what you're saying but the problem I have is that I don't know how many entries there will be because my final program will have to read a series of files created by different patients with OCD. As such, each file will have different numbers of entries.
As I was reading your post I thought to use a for-loop but then realized the problem I just stated.
Is there a way for me to count the number of entries and assign it to a variable to use for the comparison in the for-loop?
By this I mean:

1
2
3
4
5
6
7
8
9
10
11
char omonth [930][12], oday[930][10], oactvty[930][30];
int odate[930][5] = {0};
int oreps[930][8] = {0};
int i = 0; /* i is the counter for while loop*/
int num_entries; /* once found, this is the number of entries in the particular file and used to stop the for-loop*/

for(i=0; i <= num_entries; i++) /*as long as i is less than or equal to num_entries, do the following and then increment i*/
{
fscanf(Ptr, "%s %d %s %s %d", omonth[i], odate[i], oday[i], oactvty[i], oreps[i]); /* scans data for each line one-by-one and placed into corresponding container in array*/
}
printf("%s %d %s %s %d", omonth, odate, oday, oactvty, oreps); /* displays entire array */



But how would I find out where to terminate the loop? If I can find the correct value to put in num_entires would that be valid code to use?

Is this valid code to use in my for-loop?
for(i=0; (!feof(Ptr)); i++)
What does the file look like?
The number of entries is not so important as recognizing when there are not any more entries.
No, that is not the correct loop -- input is an unpleasant taskmaster.

Show us your input file and we can help you construct something appropriate.
Month	Date	Day	Activity		Repetitions
January	1	Monday	brushed_teeth		9
January	1	Monday	combed_hair		5
January	1	Monday	stepped_up_bottom_step	20
January	1	Monday	cleaned_basin 		40
January	2	Tuesday	brushed_teeth		10
January	2	Tuesday	combed_hair		10
January	2	Tuesday	stepped_up_bottom_step	10
January	2	Tuesday	cleaned_basin		20


That's exactly what my input file looks like. Sorry it didn't have the formatting in the original post. I made it as soon as I signed up. Still learning the tricks.

The output is supposed to look exactly the same (except lines 4 and 8, text wrap messes with formatting in long lines)
First recomendation: create a struct type to hold your information.

1
2
3
4
5
6
7
8
9
struct DailyTask_tag
  {
  char month[ 10 ];     // largest string: "September"
  int  day;
  char weekday[ 10 ];   // largest string: "Wednesday"
  char activity[ 30 ];  // largest string: no more than 29 characters
  int  repetitions;
  };
typedef DailyTask_tag DailyTask_t;

There are other ways to do this. I would recommend using an int for 'month' and 'weekday' as well. (You would have to transform "January" to 1, etc.)

Once you have a type that holds all the information for a single line, you need to write a function that will read a single line of information into that structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
  function ReadDailyTask()
  Attempts to read a DailyTask_t from the given FILE*, which must be open.
  Returns 1 if successful;
  Returns 0 if failure
 */
int ReadDailyTask( FILE* fp, DailyTask_t* dt )
  {
  int result = scanf(
    fp,
    "%9s %d %9s %29s %d",
    dt->month,
    &(dt->day),
    dt->weekday,
    dt->activity,
    &(dt->repetitions)
    );
  return (result == 5);
  };

Now you are set. All you need is an array of daily tasks:

1
2
DailyTask_t  daily_tasks[ 100 ];
int daily_task_count = 0;

And you need to fill it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
FILE* f = fopen( ... );

/* Remember to skip the first line */
for (;;)
  {
  int ch = fgetc( f );
  if (ch == EOF) 
    {
    fprintf( stderr, "Sorry, the file had no usable data. Bye.\n" );
    return 1;
    }
  if (ch == '\n') break;
  }

/* Read data until exhausted or failure */
while (ReadDailyTask( f, &(daily_tasks[ daily_task_count ]) ))
  daily_task_count += 1;

/* If it is not at EOF, then there was a read failure */
if (!feof( f ))
  {
  fprintf( stderr, "Alas, the input data file did not read properly! Bye.\n" );
  return 1;
  }

Now all that is left is to loop over your tasks and print them.

This is pretty much an answer. Good luck!
Thanks, Duoas. That was brilliant code but I didn't fully understand certain parts and how to manipulate them for my code since my class has only just gotten there and haven't finished the lectures.
But I did figure out my code. I basically started it over and broke it down further, reading one array, then multiple parallel arrays and then the entire file and added in a file search.
I added a condition to my for-loop and took advantage of the fact that C is loosely typed as well, changing my integers to character arrays.
Here's the code I wrote for anyone with the same problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

int main() //NOTE: this is NOT how the function is defined within the large program. It should get an appropriate function definition
{
		
		char omonth[936][10];
		char odate[936][9];
		char oday[936][10];
		char oactivity[936][36];
		char orep[936][12];
		int i, j, k;

		
		char patient_file_name[50];

		printf ("Please enter patient's filename (format: filename.txt) :");   //prompt for file name.
			scanf("%s", patient_file_name);  // store file name in a variable to allow user to search any file they want within a folder

			FILE* fptr = fopen(patient_file_name, "r");   //declare pointer and open requested file
		

			if(fptr ==  NULL)
			{
				printf("\nError opening file. Please Try again.\n");  //open file test
			}

			else{
				printf("File open successful.\n Scanning...\n");
				rewind;    // ensure pointer is at start of the file

	

				for( i=0; i < 936 && (!feof(fptr)); i++)
				{
					fscanf(fptr,"%s %s %s %s %s", omonth[i], &odate[i], oday[i], oactivity[i], &orep[i]); //scan file line-by-line
					k = i;  //using variable k to be safe in next loop
				}
				printf("%s \t\t %s \t %s \t\t %s \t %s \n", omonth[0], odate[0], oday[0], oactivity[0], orep[0]); // position 0 contains column headings
				
				for(j=1; j <= k; j++)	//variable i was far too unstable to use in second loop so value was passed to variable k.
				{
					printf("%s \t %s \t %s \t %s \t\ %s \n", omonth[j], odate[j], oday[j], oactivity[j], orep[j]); //print file line-by-line
				}
		
		fclose(fptr); //close file.
			}

		
		return 0;
}
Last edited on
Topic archived. No new replies allowed.