I am learning C and practicing by writing a small program that reads integers from a textfile and stores them into an array. However, the integers never get stored somehow and the array is empty.
int readNumbers(int array[], char* fname) {
78
79
80 int numberRead = 0;
81 FILE* fp;
82 int ch;
83 int i = 0;
84
85
86
87 fp = fopen(fname, "r");
88 // Test to see if the file was opened correctly
89
90 if (fp == NULL) {
91 printf("Error opening file\n");
92 return;
93 }
94 // Now read until end of file
95
96 while (ch = fgetc(fp) != EOF && isdigit(ch)) {
97 array[i++] = ch;
98 }
99 if (ferror(fp)) {
100 return;
101 }
102 // Close the file pointer
103
104 fclose(fp);
105
106 // Return the number of items read
107 return numberRead;
108 }
The text file would be something like this:
1 2 3 4 5 6 7 8 9
Thanks in advance.
I've updated the code. This almost works, but it interprets characters such as 55 as 5 and 5. So my array would have two 5's.
while ((ch =fgetc(fp)) != EOF) {
97 if (ch != ' ' && ch != '\n') {
98 array[counter] = ch - '0';
99 counter++;
100 numberRead++;
101 }
102 }
To expand on what Matt McNabb said in the comment, you can't have return without a value (unless it's inside a void function). Your readNumbers() function is declared to return int so all return paths must return an int. You may like to return -1 if there's a file error, since 0 is (kind of :) ) a valid number of chars to read.
Since there are spaces between the digits in your input file you will need to change the logic in your while loop.
while ((ch = fgetc(fp)) != EOF && isdigit(ch))
will fail as soon as it reads a non-digit char.
I should also mention that you are storing the numerical value of each char you read into your array, which might not be what you want. Eg, in ASCII a '0' char will have a numeric value of 48, '1' has a value of 49, etc.
PS. Make sure that the function that calls readNumbers() provides an array big enough to handle any possible result...
Try to avoid using exit() deep within your program, when practical, and just use it in main(). Also, rather than just killing your program stone dead with exit() it's much better to print some kind of error message first (usually to stderr), and then die gracefully. As for creating suitable error messages, check out the <stdio.h> function perror(), and take a look at <errno.h>.
You can either print the error message in readNumbers() and return -1, and then let the calling function (eg main()) decide if the error's so bad that the program should die. Or let the calling function handle the printing of the error message, too.
you should us the parentheses here while (ch = fgetc(fp) != EOF && isdigit(ch)) , it should be while ((ch = fgetc(fp)) != EOF && isdigit(ch)) otherwise you will store in ch the value of fgetc(fp) != EOF which is eather 1 or 0 ( TRUE or FALSE)
// this following code modification will handle your most recent question
int value = 0; // place to accumulate numbers
int inNumber = 0; // to avoid spurious input in array[]
// note: the following expects that 'ch' is defined as an integer
while ((ch =fgetc(fp)) != EOF)
{
if (ch >= '0' && ch <= '9') // only process numeric characters
{
value *= 10;
value += (ch - 0x30); // convert alpha to binary
inNumber = 1;
}
else
{ // break between numbers
if( 1 == inNumber )
{
array[counter] = value;
counter++;
numberRead++;
value = 0; // reset for next number
inNumber = 0;
}
}
}
Related
I am writing this code:
int b;
char c;
scanf("%d", &b);
while((c = getchar()) != EOF) {
if(c >= 9 || c < 0) {
printf("Invalid number!\n");
exit(0);
}
}
When I assign b, automatically c is equal to b.
For example, if my input for b is 10, it automatically goes into the if-statement and exits the code.
Does anyone know why?
Finding problems and solving them
You have plenty of errors in the code that are listed below.
The getchar(3) says:
getchar() is equivalent to getc(stdin).
The prototype of getc() is:
int getc(FILE *stream);
That is, the getchar() returns an integer (from unsigned char cast). Thus, we need to change the type from char to int to accept its return value correctly.
Note that EOF is not a valid unsigned char. It expands to signed int -1.
Never ignore the return value of the scanf(3). It returns the number of correctly passed arguments. In this case, to make the code reliable, we should put:
if (scanf("%d", &b) != 1) {
fprintf(stderr, "Value must be an integer.\n");
return EXIT_FAILURE;
}
There is a semantic error in the condition:
if (c >= 9 || c < 0)
^^____________ logically, 9 is a valid one digit number
so removing '=' from here makes more sense
One notable thing is that the condition and the type of the comparator – both should be changed. See the next step.
The fixed loop should look like:
while ((c = getchar()) != EOF) {
if (c == '\n') // Since c = getchar() can be '\n' too
continue; // so, better ignore
if (c >= '0' && c <= '9') // Change the loop like this
printf("Valid number %d %c.\n", c, c);
else
printf("Invalid number.\n");
}
Sample test case output
1
10 // --- Note: 10 are two chars for two getchars
Valid number 49 1.
Valid number 48 0.
3
Valid number 51 3.
9
Valid number 57 9.
-
Invalid number.
a
Invalid number.
<
Invalid number.
.
Invalid number.
I'm trying to read a text file of integers into an array in C.
My text file looks like this: (12 numbers/line)
5713 6936 8764 6702 8535 8654 8710 8332 4948 7627 5472 5311
7331 8719 6135 6672 5786 7113 5292 6923 5683 7020 8595 8606
6837 7003 7415 8372 8429 5726 8323 6442 8672 6488 6932 5884
6811 7785 7189 5531 6323 8561 8283 5114 6669 7217 8307 6599
6961 8695 6026 5580 6010 4954 8725 4955 5532 7736 5372 8712
8343 5375 5931 6449 8223 5844 5931 5307 5436 6405 8599 6302
8617 8222 5985 8216 5044 5259 6523 7526 8702 5878 7559 5366
5362 7393 6633 8781 6289 6470 5342 7278 5348 8677 5779 5763
5718 8678 6406 8774 5931 7324 6819 6393 5027 7545 8385 8795
8277 8059 6362 6980 5899 5828 6707 7149 5621 7287 5958 6506
6517 5710 5504 7070 8797 6840 7112 6063 7014 5419 7514 7431
The actual file has overall 1000 numbers
Currently, I am using the following code:
int main(void){
FILE *my_file;
my_file = fopen("seals.txt", "r");
size_t size = word_conter(my_file);
int weight = 0;
int seals[size];
int i;
for(i = 0; i < size; i++){
if(fscanf(my_file, "%1d", &weight) == 1)
seals[i] = weight;
else break;
}
for(i = 0; i < size; i++){
printf("%d\t %d\n", i, seals[i]);
}
fclose(my_file);
return 0;
}
EDIT: Here is word_counter :
size_t word_conter(FILE *my_file){
if(my_file == NULL){
perror("Error in file");
exit(1);
}
size_t counter = 0, in_word = 0;
char ch;
while((ch = fgetc(my_file)) != EOF){
if(ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0'){
if(in_word){
in_word = 0;
counter++;
}
}
else in_word = 1;
}
return counter;
}
Unfortunately, my output is:
0 245589760
1 1
2 1
3 0
4 -497513808
5 32766
6 245022469
7 1
8 -497513808
9 32766
10 245022268
11 1
12 1
13 0
14 224894352
15 1
16 -497513744
17 32766
18 244994643
19 1
20 245557328
21 1
22 224894352
23 1
24 224879992
25 1
26 0
27 0
28 245584536
29 1
30 245616784
31 1
32 -497513712
33 32766
34 245024298
35 1
36 245557328
37 1
38 -799666472
39 22978
40 -497510096
And so on up to 999.
I have tried using both:
fscanf(my_file, "%1d", &weight) and fscanf(my_file, "%d", &weight)
but both didn't work. I have read the manual about fscanf but still couldn't get it right.
Any help would be much appreciated!
Second Edit:
I used rewind() and that did the trick!
Word counter messes up on edge cases.
Look for transitions from space to non-space. Do not forget to rewind().
size_t counter = 0;
bool in_word = false;
// char ch;
int ch;
while((ch = fgetc(my_file)) != EOF){
if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0') { // better: if (isspace(ch)) {
in_word = false;
} else {
if (!in_word) counter++;
in_word = true;
}
}
rewind(my_file); // reset to the beginning
return counter;
Even better, just go through the file twice with the same format.
size_t counter = 0;
while (fscanf(my_file, "%d", &weight) == 1) {
counter++;
}
rewind(my_file); // reset to the beginning
In a nutshell, this is caused by reading through the data file twice in a row without calling rewind().
The problem occurs when fscanf() reads the file for a second time without rewinding. (first read is in word_conter() function):
if(fscanf(my_file, "%d", &weight) == 1)//2nd read on one file descriptor
seals[i] = weight;//program flow never gets here
else break;
This results in execution flow jumping directly to else break;, then continuing to loop on printf() and outputting the uninitialized array: int seals[size];
Also, the function word_conter is susceptible to various inconsistencies data formatting might present within the file it is reading. Suggest stepping through code in a debugger to characterize exactly how this might be contributing to the problem.
My suggestion is to call fopen() and fclose each once inside word_counter, then re-call both again in the main function. This refactored version of size_t word_conter(FILE *my_file) supports this approach. (written to accommodate file containing 12 numbers per line as per mentioned in comments):
size_t word_counter(char *filename)
{
char line[260] = {0};
char *tok = NULL;
int count = 0;
FILE *fp = fopen(filename, "r");
if(fp)
{
while(fgets(line, sizeof(line), fp))
{
tok = strtok(line, " \n");
while(tok)
{
count++;
tok = strtok(NULL, " \n");
}
memset(line, 0, sizeof(line));
}
fclose(fp);
}
return count;
}
Called in main as:
size_t size = word_counter("seals.txt");
There is also an instance of using an incorrect format specifier can invoke undefined behavior
For:
int weight = 0;
The correct format specifier is "%d". Either change:
if(fscanf(my_file, "%1d", &weight) == 1)
to:
if(fscanf(my_file, "%d", &weight) == 1)
or change:
int weight = 0;
int seals[size];
to:
long weight = 0;
long seals[size];
(%ld is used only for long.)
Addressing each of these is likely to address the problem you are seeing. (However, because word_conter() is not shown in detail, there may be other issues.)
try to replace if(fscanf(my_file, "%1d", &weight) == 1) with if(fscanf(my_file, "%d", &weight) != EOF)
I have a processes.txt file that contains details about incoming processes like so,
0 4 96 30
3 2 32 40
5 1 100 20
20 3 4 30
I wanted to find the number of lines in this file. How can that be done?
I tried this code, but it always returns the number of lines as 0
char c;
int count = 0;
// fp is the pile pointer
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
count = count + 1;
Apart from the char that should be an int your code is more or less fine. The problem is somewhere in the code you didn't show.
This works:
#include <stdio.h>
int main() {
FILE* fp = fopen("processes.txt", "r");
if (fp == NULL)
{
printf("Could not open file.");
return 1;
}
int c; // this must be an int
int count = 0;
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
count = count + 1;
printf("The file has %d line(s)\n", count);
fclose(fp);
}
However if the last line of the file does not end with a \n, it is not counted.
Please, read How to create a minimal, complete and verifiable example.
In order to test your program snippet, I first had to complete your fragment of code in order to make it compilable. Probably your error has gone with that modifications, as my run of it shows (over your input text) this output:
pru.c
#include <stdio.h>
int main()
{
char c;
int count = 0;
FILE *fp = stdin; // most probably your error is
// related to this initialization.
// fp is the pile pointer
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
count = count + 1;
printf("%d\n", count);
return 0;
}
and running it:
$ pru <<EOF
0 4 96 30
3 2 32 40
5 1 100 20
20 3 4 30
EOF
4
$ _
Which is the correct answer.
Despite of this, your program fragment, shows a non visible error, as you have been told in the comments to your question: type of c variable should be int and not char, but why?
Because char is the type you want to receive, all available values are possible, so to indicate that some special condition has been detected in your file (the end of the data in the stream, or EOF is not one of those values, but a special condition) one extra value is needed, so making the type char insufficient to include all possible return values from fgetc(3). This is the reason to make fgetc(3) function to return an int.
Check the documentation of fgetc(3) as your program works almost fine, while you have to be given a reason of why:
When the program reads a character, it is mapped into the int values 0 to 255, so all different bytes convert as positive integer values, while normally (almost every implementation does) EOF is mapped into the integer value -1. What is happening here is that all your values are converted into a char, making EOF to be mapped into one of those 0 to 256 values (which one is dependent on the implementation, but normally it is the value 255 ---or -1 if char happens to be signed) so:
in case your char type is represented as a two's complement type (signed) your values 0 to 255 are mapped into 0 to 127 and -128 to -1, and the EOF value is mapped to some of them (mostly -1).
in case your char type is represented as an unsigned type, your values 0 to 255 are mapped into 0 to 255 and the EOF value is mapped to one of them (most probably 255)
it doesn't matter which value the EOF is converted to, as you make your comparison in a coherent type system, so the converted char value is compared with the converted EOF value making that EOF is converted into the converted value of EOF. But this makes another char value to happen to show the same behaviour, making that one such charater on input will be interpreted as EOF, and will make your program to stop prematurely.
In both cases above, if a byte with the same mapped-to value of EOF is input, your program will finish, believing that it has reached the end of the file, and your count will be erroneous. This is not the case here, but you can get a surprise with one file that has such a character.
So your final program (corrected) would be:
#include <stdio.h>
int main()
{
int c;
int count = 0;
FILE *fp = stdin;
// fp is the pile pointer
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
count = count + 1;
printf("%d\n", count);
return 0;
}
Before terminating, I'll recommend to use a while loop, as it is a frequently used idiom in C to produce more compact form of your loop:
#include <stdio.h>
int main()
{
int c;
long count = 0;
FILE *fp = stdin; /* probably you dont have intialized this
* field in your code, but who knows, if
* you have not posted a complete
* sample */
// fp is the pile pointer
while ((c = getc(fp)) != EOF)
if (c == '\n') // Increment count if this character is newline
count++; // this is another frequently used idiom :)
printf("%d\n", count);
return 0;
}
Maybe your file is at the end or in error when you do this?? And you need to start at the beginning
int c; // c must be int
int count = 0;
// fp is the pile pointer
rewind(fp); // back to beginning, clear error
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
count = count + 1;
I am trying to print out the ASCII values of all the characters in a text file.
int main(int argc, char* argv[]) {
FILE *fp;
int c;
fp = fopen(argv[1], "r");
while((c = fgetc(fp)) != EOF) {
printf("%c %3d\n", c, (int)c);
}
fclose(fp);
return 0;
}
Is it possible to show the output as shown below?
r a n d o m
114 97 110 100 111 109
Assuming the first word in my input file is 'random'. Thanks
Yes, as hexiecs said, it is very possible. Asking how would be a much better question. I am going to assume this is what you mean.
Here is an example of how you might go about doing this:
#include <stdio.h>
#define NEW_TERMINAL_LINE 10
void print_current_characters(char char_equivalents[]);
int main(int argc, char const *argv[]) {
char char_equivalents[NEW_TERMINAL_LINE] = {0};
int c;
int i = 0;
int final_position; /* Store the final position that we will use later
* to get the remaining characters in the buffer */
FILE *file;
file = fopen("file.txt", "r");
if (file) {
while ((c = getc(file)) != EOF) {
if (i > NEW_TERMINAL_LINE - 1) {
/* Every time the buffer fills up, we need to go to a new line
* in the output as well (defined by NEW_TERMINAL_LINE).
* Then we need to clear the buffer and make a new line
* to start off printing again!
*/
print_current_characters(char_equivalents);
int j;
for (j = 0; j < sizeof(char_equivalents)/sizeof(char_equivalents[0]); j++) {
char_equivalents[j] = 0; /* Clear the filled up buffer */
i = 0;
}
printf("\n\n");
}
/* Print the character itself (we will print the ASCII when the buffer fills up) */
char_equivalents[i] = c;
if(char_equivalents[i] == '\n') {
printf("\\n\t");
} else if (char_equivalents[i] == '\t') {
printf("\\t\t");
} else if (char_equivalents[i] == ' ') {
printf("[space]\t");
} else {
printf("%c\t", c);
}
final_position = i;
i++;
}
/* Print any remaining characters in the buffer */
print_current_characters(char_equivalents);
fclose(file);
}
printf("\n");
return 0;
}
void print_current_characters(char char_equivalents[]) {
printf("\n");
int i;
for(i = 0; i < NEW_TERMINAL_LINE; i++) {
if (char_equivalents[i] == 0 || NULL) {
break; /* Don't print if there is nothing but 0s in the buffer */
}
if(char_equivalents[i] == '\n') {
printf("\\n\t\t");
} else if (char_equivalents[i] == '\t') {
printf("\\t\t");
} else {
printf("%d\t", (int)char_equivalents[i]); /* Print the ASCII character */
}
}
}
With my previous edit, Jonathan Leffler and I were discussing what would happen if the buffer filled up since the original poster said in a comment:
I am assuming the input file will have a maximum 1000 characters.
The output would be a very long line unless there were newlines after a certain amount of characters.
We could just have an array with a maximum buffer of 1000, but we could also save more memory by just processing the file every x amount of characters. Here, after every NEW_TERMINAL_LINE number of characters, we can create a new line and print out the current buffer. Finally we can empty the buffer, and continue processing the characters. In fact, using this approach, the buffer is only limited by the available memory on the computer.
Say we want the maximum number of characters (and the corresponding ASCII values) on a line to be displayed as 10. The text file contains the string: random random random random random random random random [enter] (Hypothetically, the string could be much longer and the program would still display it neatly). The output of this program looks like1:
r a n d o m [space] r a n
114 97 110 100 111 109 32 114 97 110
d o m [space] r a n d o m
100 111 109 32 114 97 110 100 111 109
[space] r a n d o m [space] r a
32 114 97 110 100 111 109 32 114 97
n d o m [space] r a n d o
110 100 111 109 32 114 97 110 100 111
m [space] r a n d o m [space] r
109 32 114 97 110 100 111 109 32 114
a n d o m \n
97 110 100 111 109 \n
if NEW_TERMINAL_LINE is set to 10.
We end up storing the ASCII equivalents in an array named char_equivalents. For every character we come across, we store it in the array, and then we print it out followed by a tab.
Once the buffer array is full, we move down a line, loop through the array, and print out the ASCII values with formatting:
Since chars are essentially ints in disguise as ASCII, we simply typecast the char as an int. This will print out the corresponding ASCII value. Afterwards, we add a tab to make sure everything aligned with the line above. With this information, it is not difficult to loop through the array and print out the corresponding information.
We finally reset the buffer, and print the blank new line seen after NEW_TERMINAL_LINE characters for clarity.
The buffer is filled and reset until we have printed all of the characters in the file (the previous steps are repeated).
In the end, sometimes the buffer isn't full so we never printed out the remaining ASCII equivalents for the last line in the output. We simply call print_current_characters() again.
1 I don't really think this was the best way to format the code, but at the same time, I did want to honor the format that the original post asked for.
It will become more convenient if you process individual words instead of each characters. This way you can print each individual characters of the words first, and then print ASCII values of each characters the words next.
You can do try something like this.
int main(int argc, char* argv[]) {
FILE *fp;
int c;
char line[100]; /* Buffer to hold each line */
fp = fopen(argv[1], "r");
/* get each line, and print each word of the line */
while (fgets(line, 100, fp) != NULL) {
line[strlen(line) - 1] = '\0';
print_words(line);
}
fclose(fp);
return 0;
}
/* print_words: print each word from line */
void print_words(char *line)
{
char *word;
/* get each word, and print them with ascii values */
if ((word = strtok(line, " ")) != NULL)
ascii_print(word);
while ((word = strtok(NULL, " ")) != NULL)
ascii_print(word);
}
/* ascii_print: print each char and its ascii values for a word*/
void ascii_print(char *word)
{
int i, len;
len = strlen(word);
/* print the word */
for(i = 0; i < len; i++)
printf("%-4c", word[i]);
printf("\n");
/* print ascii values */
for(i = 0; i < len; i++)
printf("%-4d", word[i]);
printf("\n");
}
Note that above program is not totally correct, and may produce buggy results in some test cases. However it shows the idea that it is easier if you process word by word, instead of character by character.
Although, the code is simple, you may have to see manual pages of fgets() and strtok() if you are not familiar with them.
Briefly saying, fgets() gets a line from a file, and strtok() gets each word from a line. For more info, you need to do man 3 strtok and man 3 fgets in Google (or in command line if using Unix-like machine).
You can first use a buffer to record the input in a line, then you can show the ASCII values of the input by transferring the characters in the buffer to integers in the following line.
I have an a method that reads input and prints ascii characters to a file stream.
Originally it didn't need to print to a file so I used putchar and it worked fine
but now that I use putc or fputc it prints every other input.
Example:
input = test
Output = t s
int readFile(char* input,FILE* inputFile)
{
int anyChanges = 1;
int iochar = 0;
int i = 0;
//credit Foster Chapter 2
while (( iochar = getc(inputFile) ) != EOF )
{
//Returns 1 if no changes made, return 0 if any changes have been made.
// printf("\t character --> %c",iochar);
//printf("\nGot to first while loop\n");
if(iochar != '\n')
{
// printf("Got to second loop\n");
int printedColumns =0;
input[i] = iochar;
printf("input array ---> %c\n",input[i]);
i++;
printf("i:%d\n",i);
printf("iochar:%d\n",iochar);
//This if statement checks for normal ascii characters.
//If the output is less than 72 it prints it and increments printedColumns.
if (( ' ' <= iochar ) && ( iochar <= 126 ) )
{
fputc(input[i],inputFile);
}
}
}
}
Here for getc & putc you are using same Stream pointr i.e. inputFile , you want to read and write onto same file ??
did you mean to fputc iochar instead of input[i] (since you already incremented i)?
http://www.cplusplus.com/reference/cstdio/fputc/ states that the position indicator is incremented.