I would like to read 3-digit-numbers with spaces inbetween from a file with the fgetc()-command and put them into an array, which is not currently working, as the resulting array has completely different objects in it. What am I doing wrong? (I used a file with "107 313 052 614" in it, resulting in the output "5435 5641 5380 5942")
My Code:
#include<stdio.h>
#include<stdlib.h>
void print_array(int* arrayp, int lengthp){
int i;
for(i=0;i<lengthp;i++){
printf("%i ", arrayp[i]);
}
return;
}
int main(){
int length=1;
int i;
FILE *fp1;
fp1 = fopen("durations.txt", "r");
fgetc(fp1);fgetc(fp1);fgetc(fp1);
while(fgetc(fp1)!=EOF){
length++;
fgetc(fp1);
fgetc(fp1);
fgetc(fp1);
}
fclose(fp1);
int* list = (int*) malloc(sizeof(int)*length);
FILE *fp2;
fp2 = fopen("durations.txt", "r");
for(i=0;i<length;i++){
list[i]=0;
list[i]+=100*(fgetc(fp2));
list[i]+=10*(fgetc(fp2));
list[i]+=(fgetc(fp2));
fgetc(fp2);
}
fclose(fp2);
print_array(list, length);
return 0;
}
The characters that are used to store digits in a "readable" file are not "numbers". The most popular encoding is ascii character encoding, ex. the 1 digit is represented with the number 49 in decimal.
Because the 0, 1, 2 ... 9 digits in ascii encoding are encoded in increasing order, you can just substract 48 (ie. '0' character) to convert a digit character to it's machine format Just - '0'.
Change you loop into:
for(i=0;i<length;i++){
list[i]=0;
list[i]+=100*(fgetc(fp2) - '0');
list[i]+=10*(fgetc(fp2) - '0');
list[i]+=(fgetc(fp2) - '0');
fgetc(fp2);
}
This also explains the current output of your program. If you don't substract '0' from the numbers, then for example for 107 you get:
100 * '1' + 10 * '0' + '7' =
100 * 49 + 10 * 48 + 55 =
5435
The 49, 48 and 55 are decimal values for digits 1, 0 and 7 in ascii table.
The problem is that your are reading in the (probably) ASCII values of each digit and assuming that is the value of the digit. You need to subtract the value of the zero character from each value, like this:
for (i = 0; i < length; i++) {
list[i] = 0;
list[i] += 100 * (fgetc(fp2)-'0');
list[i] += 10 * (fgetc(fp2)-'0');
list[i] += (fgetc(fp2)-'0');
fgetc(fp2);
}
This will work even if your system doesn't use ASCII encoding.
It might be simpler to just read the numbers into cstrings then use the stdlib function atoi to convert each string to a number before loading into the array of ints:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
//open the file for reading with error checking:
FILE* fp;
char c = '0';
int length = 0;
fp = fopen("durations.txt", "r");
if (fp == NULL) {
printf("Could not open file\n");
return 0;
}
//count the number of lines in a EOF-terminated string w/o newlines
for (c = fgetc(fp); c != EOF; c = fgetc(fp)) {
if (c == ' ') {
length += 1;
}
}
rewind(fp); //go back to file end w/o needing close/open
//Then, assuming only spaces are between numbers (so length = length + 1)
char buffer[4];
int* lst = (int*) malloc(sizeof(int)*length);
for (int i = 0; i < length + 1; i++) {
fscanf(fp, "%s", buffer); //stops at spaces
lst[i] = atoi(buffer);
}
//close the file with error checking
int check = fclose(fp);
if (check != 0) {
printf("File close failed");
return 0;
}
for (int i = 0; i < length + 1; i++) { //print result
printf("%d\n", lst[i]);
}
free(lst); //clean up memory after use
lst = NULL;
return 0;
}
Related
Can any one explain to me how to make a C program to read input from a file according to the following scenario:
12
2-4,7,9;
1,4,11-12;
1,4,10,12;
1,4-8,10-12;
1,8;
1,3-6,8,10-12;
1,3,5-6,8,11;
1,8,10-12;
1-8;
;
2;
2-4,7-10,12;
The first number (on the first line) describes what size the grid should be, in this case a 12x12 grid. The following lines describe how many cells are occupied on each row of the grid. For example, in the first row the cells from 2 to 4 and 7 and 9 are occupied; in the second row, the cells 1, 4 and from 11 to 12 are occupied and so on.
Right now I have this code, but it is not solving my problem ...
#include <stdio.h>
#include <stdlib.h>
void main()
{
char content[3000];
int value;
FILE *ptr_file = fopen("data.txt", "r");
if(!ptr_file)
return 1;
int j;
while(fgets(content, 3000, ptr_file)!=NULL){
printf("%s", content);
value = atoi(content);
for(j=0; j<3000; j++){
value = content[j];
printf("%i", value);
}
}
return 0;
}
Console throws just a bunch of random numbers ...
Pseudo-code:
Open your file
Read the first line
Extract the value N
Allocate your grid
Loop N times
Read a line
If not an empty line, ie. semi-colon only
Split into tokens by comma
Check for a range or a single digit
Extract numbers
Set cells accordingly
The "random" numbers are the byte values from your file and you forgot to stop at end of line.
Dave's solution is not quite right for c.
After read a line:
while not semicolon
strtoul a number
if no number
exit error
if next char is hyphen
shift to next char
strtoul end of range
if no number
exit error
set cells
else
set cell
if next char is not semicolon
shift to next char
You should not use atoi for anything ever. Use sscanf or strto….
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
enum { EOD = -1, EOL = -2, ERR = -3, OFF = 0, ON = 1 };//End Of Data, End Of Line
int getValue(FILE *fp){
static int on_yield = OFF, prev, end;
if(on_yield == ON && prev < end){
return ++prev;
}
on_yield = OFF;
int n, ch = fgetc(fp);
if(ch == EOF)
return EOD;
else if(ch == ';')
return EOL;
else if(ch == ',' || ch == '\n')
return getValue(fp);//or change to using loop
else if(isdigit(ch)){
ungetc(ch, fp);
fscanf(fp, "%d", &n);
return prev=n;
} else if(ch == '-'){
on_yield = ON;
fscanf(fp, "%d", &n);
end = n;
return getValue(fp);
}
fprintf(stderr, "(%c) invalid format in file\n", ch);
return ERR;
}
int main(void){
FILE *ptr_file = fopen("data.txt", "r");
if(!ptr_file){
perror("fopen");
return 1;
}
int size;
fscanf(ptr_file, "%d", &size);//check omitted
char (*cell)[size] = malloc(size * sizeof(*cell));
memset(&cell[0][0], ' ', size*size);
int r = 0, c, value;
while((value=getValue(ptr_file))!=EOD){
if(value == EOL){
++r;
continue;
}
if(value > 0)
cell[r][value-1] = '*';
}
fclose(ptr_file);
for(r = 0; r < size; ++r){
for(c = 0; c < size; ++c){
putchar(cell[r][c]);
}
putchar('\n');
}
free(cell);
return 0;
}
I am trying to take all the integers from the file file.txt and place them in a dynamically allocated array. However the file could also contain other characters, and these should not be put in the array.
The file contains the following:
2 -34 56 - 23423424
12example-34en+56ge-tal345
int* getIntegers(char* filename, int* pn)
{
FILE* fileInput = fopen(filename, "r");
int* temp = (int*)malloc( 100*sizeof(int));
int counter = 0;
int c= fgetc(fileInput);
while(c != EOF){
counter ++;
printf("%d;\t%d\n", counter, c);fflush(stdout);
temp[counter++] = c;
}
*pn = counter;
return (temp);
}
int main(void)
{
int n;
int* a = getIntegers("file.txt", &n);
if (a != NULL){
puts("numbers found:");
for (int i = 0;i < n; i++){
printf("%d ",a[i]);
}
free(a);
}
putchar('\n');
while(getchar()== '\n');
return (EXIT_SUCCESS);
}
when I run this the following output is returned:
Output:
1; 49
3; 49
5; 49
7; 49
9; 49
11; 49
13; 49
15; 49
17; 49
19; 49
21; 49
While the correct output should have been
found numbers:
12 -34 56 23423424 12 -34 56 345
There are many things wrong with that program.
You leak your file object. You should close it with fclose() when done.
If there are more than 100 numbers in your input, you will overflow your buffer, trash your stack, and do Bad Things to your program.
You increment your counter twice at every loop iteration, so you'll skip every second entry in your output array.
You never read another byte from the input, so you're just going to keep processing the same byte over and over in an infinite loop until your buffer overflow causes your program to crash.
You never convert the digits that you read from your input file into an integer; instead, you just take the character code. 49 is the ASCII/UTF-8 code for '1', which appears to be the first character in your input.
try this
#include <stdlib.h>
#include <stdio.h>
int* getIntegers(char* filename, int* pn)
{
int* temp = (int*)malloc( 100*sizeof(int));
int counter = 0;
int result;
int c;
FILE* fileInput = fopen(filename, "r");
if ( fileInput == NULL) {
return temp; // return if file open fails
}
while( 1) {
result = fscanf (fileInput, "%d", &c);//try to read an int
if ( result == 1) { // read successful
temp[counter] = c; //save int to array
counter++;
printf("%d;\t%d\n", counter, c);
}
else { // read not successful
fscanf ( fileInput, "%*[^-+0-9]"); //scan for anything not a -, + or digit
}
if ( counter > 98) { // dont exceed array
break;
}
if ( feof( fileInput)) { // check if at end of file
break;
}
}
fclose ( fileInput); // close the file
*pn = counter;
return (temp);
}
int main(void)
{
int n;
int i;
int* a = getIntegers("file.txt", &n);
if (a != NULL){
printf("numbers found:");
for (i = 0;i < n; i++){
printf("%d ",a[i]);
}
free(a);
}
putchar('\n');
return (EXIT_SUCCESS);
}
Many loop holes in your code.You need to first fix it.
int c= fgetc(fileInput);
while(c != EOF)
{
counter ++;
printf("%d;\t%d\n", counter, c);fflush(stdout);
temp[counter++] = c;
}
This code make me crazy. What you gain by reading only one character from file and run while loop? Give chance to read another byte.
Must check the return value fopen function. what if files not present OR error in opening? Your program gone wild. So ensure
FILE* fileInput = fopen(filename, "r");
if(fileInput==NULL ){
printf("Error to open file\n");
return
}
Also you incremented counter two times in loop first one is counter ++; and second one is temp[counter++] = c; this is wrong to manage array index.
Also most important thing is every open file must be close.
I want to make a program which reads the text from a file and shows every character, the ASCI code of each one and the number of occurrences.
I wrote this but it doesn't show the occurrences.
#include <stdio.h>
#include <stdlib.h>
int main ()
{
FILE * pFile;
int i=0;
int j=0;
char text[j];
int ascii[256];
int occ[256];
int occurance=0;
int position;
pFile = fopen ("c:/1.in","r");
if (pFile==NULL) perror ("Error opening file");
else
{
while (!feof(pFile)) {
j++;
text[j]=getc (pFile);
ascii[j]= (int) text[j];
position=ascii[j];
occ[position]++;
}
for (i=1;i<j;i++){
occurance=position[i]
printf ("Chracter %c has ascii %d and occurs %d times \n", text[i],ascii[i],occ[occurance] );}
}
system("PAUSE");
return 0;
}
First, I don't see the point in this:
int j=0;
char text[j];
If you want to put every character in the file into an array then read the size of the file and malloc() the correct size to a pointer. But why do that anyway? If you're trying to count ever occurrence of ever character then just keep track of the possibilities.
For completeness you can use an array of 256 characters, but in reality if you're just looking at standard printable characters there should only be about 94.
This:
int main ()
{
int temp = 0, i;
int occ[256] = {0};
FILE * pFile = fopen("test.txt", "r");
if (pFile == NULL) perror("Error opening file");
else {
while (!feof(pFile)) {
temp = getc(pFile);
if((temp < 255) && (temp >= 0))
occ[temp]++;
}
}
//reads every character in the file and stores it in the array, then:
for(i = 0; i<sizeof(occ)/sizeof(int); i++){
if(occ[i] > 0)
printf(" Char %c (ASCII %#x) was seen %d times\n", i, i, occ[i]);
}
return 0;
}
will print every character, the ASCII code (in hex) and the number of times it showed.
An example input file of:
fdsafcesac3sea
yeilds an output of:
Char 3 (ASCII 0x33) was seen 1 times
Char a (ASCII 0x61) was seen 3 times
Char c (ASCII 0x63) was seen 2 times
Char d (ASCII 0x64) was seen 1 times
Char e (ASCII 0x65) was seen 2 times
Char f (ASCII 0x66) was seen 2 times
Char s (ASCII 0x73) was seen 3 times
Below simple logic works fine for me. Add file operations to get the buf.
int main()
{
char buf[] = "abcaabde";
char val[256] = {0};
int i = 0;
for (i = 0; i < sizeof(buf); i++)
{
val[buf[i]]++;
}
for (i = 0; i < 256; i++)
{
if (val[i] != 0)
{
printf("%c occured %d times\n", i, val[i]);
}
}
return 0;
}
Output is
occured 1 times
a occured 3 times
b occured 2 times
c occured 1 times
d occured 1 times
e occured 1 times
I have written a small program which takes input of a file such as:
13,22,13,14,31,22, 3, 1,12,10
11, 4,23, 7, 5, 1, 9,33,11,10
40,19,17,23, 2,43,35,21, 4,34
30,25,16,12,11, 9,87,45, 3, 1
1,2,3,4,5,6,7,8,9,10
and outputs the largest sum of numbers on each line that is less than 50.
However if the inputted file has a trailing newline character the loop runs one too many times and hence another line is added to the array with random data. So I'm looking for a better way to do this comparison to avoid this issue. I'm also assuming all lines have 10 integers on at the moment as i cannot think of a better way to do the end of line loop comparison.
#include <stdio.h>
#include <stdlib.h>
void readLineData(int lineNo, int val[][10], FILE *fp);
int findSum(int lineNo, int val[][10], FILE *fp);
int main(int argc, char *argv[]) {
FILE *fp;
int val[5][10];
// Open file.
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Cannot open file ");
exit(EXIT_FAILURE);
}
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
}
fclose(fp);
return EXIT_SUCCESS;
}
void readLineData(int lineNo, int val[][10], FILE *fp) {
char c;
for (int i = 0; i < 10; i++) // assuming line contains 10 integers
{
fscanf(fp, "%d,", &val[lineNo][i]);
}
}
int findSum(int lineNo, int val[][10], FILE *fp) {
int highVal = 0;
int value1 = 0;
int value2 = 0;
for(int i = 0; i < 10; i++) //each letter
{
for(int j = 0; j < 10; j++)// every other letter
{
if((val[lineNo][i] + val[lineNo][j]) > highVal && i != j && (val[lineNo][i] + val[lineNo][j]) <= 50)
{
highVal = val[lineNo][i] + val[lineNo][j];
value1 = val[lineNo][i];
value2 = val[lineNo][j];
}
}
}
printf("Line %d: largest pair is %d and %d, with a total of: ", lineNo+1, value1, value2);
return highVal;
}
any help with those loop comparisons and general notation tips is most welcome.
Thanks
The posted code does not distinguish between two lines that have five integers and (the expected) one line that has 10 integers. Suggest reading in a line at a time, using fgets() and then using sscanf() on the read line to ensure that all the read integers belong to the same line.
Check the return value of input operations. For example, sscanf() (and fscanf()) return the number of assignments made. Only process lines that have the expected 10 integers, which would detect invalid lines including the trailing empty line.
For example:
/* Returns 1 on success and 0 on failure. */
int readLineData(int lineNo, int val[][10], FILE *fp)
{
char line[1024]; /* Arbitrarily large. */
if (fgets(line, sizeof(line), fp))
{
/* %n records position where processing ended. */
int pos;
const int result = sscanf(line,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
&val[lineNo][0],
&val[lineNo][1],
&val[lineNo][2],
&val[lineNo][3],
&val[lineNo][4],
&val[lineNo][5],
&val[lineNo][6],
&val[lineNo][7],
&val[lineNo][8],
&val[lineNo][9],
&pos);
/* 10 integers and full line processed,
except if new-line character present. */
return 10 == result &&
(pos == strlen(line) ||
(pos + 1 == strlen(line) && '\n' == line[pos]));
}
return 0;
}
You could simply consume the newline character yourself:
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
fscanf(fp, "%*c"); // read a character without storing it in a variable
}
Note that there are undoubtedly better ways that involve reading an entire line at once and simply examining its contents; but this is the easiest way that will fit with what you already have.
you could check if fscanf fails in your readLineData function:
int readLineData(int lineNo, int val[][10], FILE *fp) {
for (int i = 0; i < 10; i++) {// assuming line contains 10 integers
if (fscanf(fp, "%d,", &val[lineNo][i]) != 1) {
return 1;
}
}
return 0;
}
12 23 34 45 56
34 23 56 21 43
12 57 98 34 12
The above is the content of a txt file.
With C, i can use fgetc(myFile) to get the first integer and store into an integer variable.
I will check whether it is 12.
if it is 12, i want to replace with 25. How do i exactly replace it a certain number.
How do i rewrite a certain part of it?
Or do i store every number into an array, replace all 12s with another numbers and overwrite the whole file??
Save result to another file, than renames it. This code opens homework.txt, replaces all 12 -> 25 and writes result to homework_new.txt
#include <stdio.h>
#include <string.h>
#define MAXBUF 42
#define HOMEWORKFILE "homework.txt"
#define HOMEWORKNEWFILE "homework_new.txt"
int main(int argc, char **argv)
{
char buf[MAXBUF+1];
char str[MAXBUF+1];
FILE *hw;
FILE *hw_new;
int length;
int i, j;
int number;
char is_first;
int n_line = 0;
hw = fopen(HOMEWORKFILE, "r");
hw_new = fopen(HOMEWORKNEWFILE, "w");
if (!hw)
{
fprintf(stderr, "File not found: %s\n", HOMEWORKFILE);
return 5;
}
while(!feof(hw))
if (fgets(buf, MAXBUF, hw) != NULL)
{
length = strlen(buf);
j = 0;
str[0] = 0;
is_first = 1;
n_line++;
/* parse string */
for(i = 0; i < strlen(buf); ++i)
{
if (isblank(buf[i]) || buf[i] == '\0' || buf[i] == '\n')
{
str[j] = 0;
number = atoi(str);
if (is_first)
is_first = 0;
else
fprintf(hw_new, " ");
if (number == 12)
fprintf(hw_new, "%d", 25);
else
fprintf(hw_new, "%d", number);
j = 0;
}
else if (isdigit(buf[i]))
{
str[j++] = buf[i];
}
else
{
fprintf(stderr, "bad input on line %d '%s'\n", n_line, buf);
return 100;
}
}
fprintf(hw_new, "\n");
}
fclose(hw_new);
fclose(hw);
return 0;
}
If it's a small file , to overwrite the whole file is a good idea and easier.
If it's not limited in c language, you can try powerful tools like "sed" or some script language.
Here's a list:
fgets
ftell
fseek
fputs
Note that you need to ensure the correct lengths of the data written, in order to overwrite exactly what you want.
Another option would be, as you said, to overwrite the whole file, then you also need
freopen