I'm learning to program in C, and right now my homework is like this. I am supposed to be able to take a text file with words/letters and my program should print the ascii codes+1 of the letters it gets. It's "encoding" it. So for example the letter "A" would be printed as 066. So my problem is the program needs to also be able to decode those ascii codes back to letters, but I don't know how to get my program to read 3 numbers at once. I used
c = fgetc(pF);
while (c != EOF) {
fprintf(pF2,"%03i",c+1);
c = fgetc(pF);
to read the file one character at a time. Should I use something similar to get the 3 numbers I need, or would it be something completely different?
#include "stdio.h"
#include "stdlib.h"
int encode(){
char * fName = "testR.txt";
char * fName2="testW.txt";
FILE * pF;
FILE * pF2;
char c, cArray[500];
int i=0;
pF = fopen(fName, "r");
if ( pF == NULL ) {
printf("Error: The specified file could not be opened.\n");
return -1;
}
pF2 = fopen(fName2, "w");
c = fgetc(pF);
while (c != EOF) {
fprintf(pF2,"%03i",c+1);
c = fgetc(pF);
}
fclose(pF);
fclose(pF2);
return;
}
char decode(){
char * fName = "testW.txt";
char * fName2="testW2.txt";
char * buf;
FILE * pF;
FILE * pF2;
char cArray[500];
char buffer[4];
buffer[3] = '\0';
pF = fopen(fName, "r");
if ( pF == NULL ) {
printf("Error: The specified file could not be opened.\n");
return -1;
}
pF2 = fopen(fName2, "w");
while (fread(buffer, 3, 1, stdin)){
putchar((atoi(buffer)-1) & 0xFF);
}
fclose(pF);
fclose(pF2);
}
int main (int argc, char *argv[]){
char c;
if ( argc != 2 ) {
printf("Incorrect number of arguments.\n");
exit(-1);
}
if (strcmp(argv[1], "-e") == 0){
encode();
}
if (strcmp(argv[1], "-d") == 0){
decode();
}
return 0;
}
I am aware that my code is a mess and there are probably things that shouldn't be there from all the changes I've been trying to make =[
Encoding:
int c;
while ((c = getchar()) != EOF)
printf("%.3d", (c+1)&0xFF);
Decoding:
char buffer[4];
buffer[3] = '\0';
while (fread(buffer, 3, 1, stdin))
putchar((atoi(buffer)-1) & 0xFF);
Technically, if the output does not end with a newline when encoding, the output is not a text file. There's no error checking on the input. The fread() will return 1 when it reads a triplet of characters; otherwise, it will return 0.
Working Programs
e3.c — encryption
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF)
printf("%.3d", (c+1)&0xFF);
return 0;
}
d3.c — decryption
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char buffer[4];
buffer[3] = '\0';
while (fread(buffer, 3, 1, stdin))
putchar((atoi(buffer)-1) & 0xFF);
return 0;
}
Sample output
$ e3 < e3.c
036106111100109118101102033061116117101106112047105063011011106111117033110098106111041119112106101042011124011033033033033106111117033100060011011033033033033120105106109102033041041100033062033104102117100105098115041042042033034062033070080071042011033033033033033033033033113115106111117103041035038047052101035045033041100044050042039049121071071042060011033033033033115102117118115111033049060011126011011$
$
The dollar at the end of the line is the prompt.
$ e3 <e3.c | d3
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF)
printf("%.3d", (c+1)&0xFF);
return 0;
}
$ e3 <e3.c | d3 | diff e3.c -
$
Basic round-tripping the encoding and decoding shows that the code works.
while (fread(buf, 1, 3, pF) == 3)
{
...
}
Related
I need to read a text file (E3-5.txt), and search for character c1 to be replaced by c2.
This is my incomplete code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char c;
char c1 = 'm';
char c2 = 'a';
int i;
FILE* fp;
fp = fopen("C:\\E3-5.txt", "r+");
if (fp == NULL)
{
printf("File not found!");
return 0;
}
for(c = getc(fp); c != EOF; c = getc(fp))
{
if(c == 'm')
{
i = ftell(fp);
printf("\nPosition %d", i);
}
}
}
I am having trouble how to locate the position of c1 in the text and how to rewrite it.
Edit:
I used the code from the answer, but it didn't change the text.
This is the new code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char c;
char c1 = 'm';
char c2 = 'a';
int i;
FILE* fp;
fp = fopen("C:\\E3-5.txt", "rb+");
if (fp == NULL)
{
printf("File not found!");
return 0;
}
else
{
for(c = getc(fp); c != EOF; c = fgetc(fp))
{
if(c == c1)
{
fseek(fp, -1, SEEK_CUR);
fputc(c2, fp);
}
else
{
return 0;
}
}
}
return 0;
}
The program returned 0 without writing anything in the text
Here you have a very naive one:
int freplace(FILE *f, char needle, char repl)
{
int result = 1;
int c;
if(f)
{
while((c = fgetc(f)) != EOF)
{
if(c == needle)
{
fseek(f, -1, SEEK_CUR);
fputc(repl, f);
//all I/O functions require error handling
}
}
}
return result;
}
getc() returns an int so you need to declare int c not char c to check for the EOF.
ftell() gets the location. Use fwrite() or fputc() to write to file at that location by setting with fseek().
Go to https://en.cppreference.com/w/c for reference. Lots of beginners fail to read all of the standard library functions, and some even reinvent the wheel.
You really don't want to directly manipulate a file. Ever. Doing so is just asking for data corruption. Instead, create a new file and move it when you're done. Also, it's a lot easier to write the code. You can do so with something like:
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int c1 = argc > 1 ? argv[1][0] : 'm';
int c2 = argc > 2 ? argv[2][0] : 'a';
const char *path = argc > 3 ? argv[3] : "stdin";
FILE *in = argc > 3 ? fopen(path, "r") : stdin;
if( in == NULL ){
perror(path);
return 1;
}
FILE *out = stdout;
char tmp[1024] = ".tmpXXXXX";
char *outpath = "stdout";
if( argc > 3 ){
outpath = tmp;
int fd = mkstemp(tmp);
if( fd == -1 ){
perror("mkstemp");
return 1;
}
if( (out = fdopen(fd, "w")) == NULL ){
perror(tmp);
return 1;
}
}
int c;
while( (c = fgetc(in)) != EOF ){
if( c == c1 ){
c = c2;
}
if( fputc(c, out) == EOF ){
perror(outpath);
return 1;
}
}
if( argc > 3 ){
if( fclose(out) ){
perror(outpath);
return 1;
}
if( rename(outpath, path) ){
perror(path);
return 1;
}
}
return 0;
}
String replace
Just for completeness, here is a bit of code to replace a word in a file! This will replace a single character, so of course it answers the question and shows some useful examples.
This is also my first and only non-trivial golden program, written in May 1994! Although you can certainly find fault with it, it worked as intended and my co-workers and I used it many different ways for sysadmin-related tasks. Compiled on MS C/C++
#include <stdio.h>
#include <string.h>
#define err(e) {_fcloseall(); fprintf(stderr, \
"USAGE: chg source dest oldstr newstr\n%s\n",e); exit(1);}
main (int argc,char *argv[])
{
FILE *in,*out;
char buffer[200];
char *old,*new;
int i,j,k;
if (argc!=5)
err("invalid # of parameters");
if ((in=fopen(argv[1],"r"))==NULL)
err("Can't open source");
if ((out=fopen(argv[2],"w"))==NULL)
err("Can't open dest");
old=argv[3];
new=argv[4];
if (*old=='"')
old++;
if (*new=='"')
new++;
if (i=strlen(old) && old[i-1]=='"')
old[i-1]=0;
if (i=strlen(new) && new[i-1]=='"')
new[i-1]=0;
if (!*old)
err("Can't search for nothing!");
if (!*new)
err("Can't replace nothing!");
j=0;
while (!feof(in))
{
if ((buffer[j]=fgetc(in))==EOF)
break;
buffer[j+1]=0;
j++;
if (!old[j-1])
{
fprintf(out,new);
fputc(buffer[j-1],out);
j=0;
}
else if (_strnicmp(buffer,old,j))
{
fprintf(out,buffer);
j=0;
}
else if (j>195)
err("Internal error, buffer filled past 195");
}
}
I try to count the number of characters, words, lines in a file.
The txt file is:
The snail moves like a
Hovercraft, held up by a
Rubber cushion of itself,
Sharing its secret
And here is the code,
void count_elements(FILE* fileptr, char* filename, struct fileProps* properties) // counts chars, words and lines
{
fileptr = fopen(filename, "rb");
int chars = 0, words = 0, lines = 0;
char ch;
while ((ch = fgetc(fileptr)) != EOF )
{
if(ch != ' ') chars++;
if (ch == '\n') // check lines
lines++;
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\0') // check words
words++;
}
fclose(fileptr);
properties->char_count = chars;
properties->line_count = lines;
properties->word_count = words;
}
But when i print the num of chars, words and lines, outputs are 81, 18, 5 respectively
What am i missing?
(read mode does not changes anything, i tried "r" as well)
The solution I whipped up gives me the same results as the gedit document statistics:
#include <stdio.h>
void count_elements(char* filename)
{
// This can be a local variable as its not used externally. You do not have to put it into the functions signature.
FILE *fileptr = fopen(filename, "rb");
int chars = 0, words = 0, lines = 0;
int read;
unsigned char last_char = ' '; // Save the last char to see if really a new word was there or multiple spaces
while ((read = fgetc(fileptr)) != EOF) // Read is an int as fgetc returns an int, which is a unsigned char that got casted to int by the function (see manpage for fgetc)
{
unsigned char ch = (char)read; // This cast is safe, as it was already checked for EOF, so its an unsigned char.
if (ch >= 33 && ch <= 126) // only do printable chars without spaces
{
++chars;
}
else if (ch == '\n' || ch == '\t' || ch == '\0' || ch == ' ')
{
// Only if the last character was printable we count it as new word
if (last_char >= 33 && last_char <= 126)
{
++words;
}
if (ch == '\n')
{
++lines;
}
}
last_char = ch;
}
fclose(fileptr);
printf("Chars: %d\n", chars);
printf("Lines: %d\n", lines);
printf("Words: %d\n", words);
}
int main()
{
count_elements("test");
}
Please see the comments in the code for remarks and explanations. The code also would filter out any other special control sequences, like windows CRLF and account only the LF
Your function takes both a FILE* and filename as arguments and one of them should be removed. I've removed filename so that the function can be used with any FILE*, like stdin.
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
typedef struct { /* type defining the struct for easier usage */
uintmax_t char_count;
uintmax_t word_count;
uintmax_t line_count;
} fileProps;
/* a helper function to print the content of a fileProps */
FILE* fileProps_print(FILE *fp, const fileProps *p) {
fprintf(fp,
"chars %ju\n"
"words %ju\n"
"lines %ju\n",
p->char_count, p->word_count, p->line_count);
return fp;
}
void count_elements(FILE *fileptr, fileProps *properties) {
if(!fileptr) return;
properties->char_count = 0;
properties->line_count = 0;
properties->word_count = 0;
char ch;
while((ch = fgetc(fileptr)) != EOF) {
++properties->char_count; /* count all characters */
/* use isspace() to check for whitespace characters */
if(isspace((unsigned char)ch)) {
++properties->word_count;
if(ch == '\n') ++properties->line_count;
}
}
}
int main() {
fileProps p;
FILE *fp = fopen("the_file.txt", "r");
if(fp) {
count_elements(fp, &p);
fclose(fp);
fileProps_print(stdout, &p);
}
}
Output for the file you showed in the question:
chars 93
words 17
lines 4
Edit: I just noticed your comment "trying to count only alphabetical letters as a char". For that you can use isalpha and replace the while loop with:
while((ch = fgetc(fileptr)) != EOF) {
if(isalpha((unsigned char)ch)) ++properties->char_count;
else if(isspace((unsigned char)ch)) {
++properties->word_count;
if(ch == '\n') ++properties->line_count;
}
}
Output with the modified version:
chars 74
words 17
lines 4
A version capable of reading "wide" characters (multibyte):
#include <locale.h>
#include <stdint.h>
#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
typedef struct {
uintmax_t char_count;
uintmax_t word_count;
uintmax_t line_count;
} fileProps;
FILE* fileProps_print(FILE *fp, const fileProps *p) {
fprintf(fp,
"chars %ju\n"
"words %ju\n"
"lines %ju\n",
p->char_count, p->word_count, p->line_count);
return fp;
}
void count_elements(FILE *fileptr, fileProps *properties) {
if(!fileptr) return;
properties->char_count = 0;
properties->line_count = 0;
properties->word_count = 0;
wint_t ch;
while((ch = fgetwc(fileptr)) != WEOF) {
if(iswalpha(ch)) ++properties->char_count;
else if(iswspace(ch)) {
++properties->word_count;
if(ch == '\n') ++properties->line_count;
}
}
}
int main() {
setlocale(LC_ALL, "sv_SE.UTF-8"); // set your locale
FILE *fp = fopen("the_file.txt", "r");
if(fp) {
fileProps p;
count_elements(fp, &p);
fclose(fp);
fileProps_print(stdout, &p);
}
}
If the_file.txt contains one line with öäü it'll report
chars 3
words 1
lines 1
and for your original file, it'd report the same as above.
I am using CodeBlocks on Windows to compile.
Why the program gives me this answer? Why there are so much as and don't get the answer 123456abcdef?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
char s[100] = "abcdef";
char c1 = '0';
int i = 0;
fp = fopen("ot.txt", "w");
if (fp == NULL) {
printf("file open error");
exit(0);
}
while (s[i] != '\0') {
fputc(s[i], fp);
i++;
printf("%d", i);
}
while (c1 != EOF) {
c1 = fgetc(fp);
putchar(c1);
}
fclose(fp);
}
There are multiple problems in your code:
c1 should be defined with type int to accommodate for all values returned by fgetc(). a char cannot unambiguously store EOF.
You should open the file in write+update mode "w+"
You should rewind the stream pointer before reading back from it for 2 reasons: a seek operation is required between read and write operations and you want to read the characters from the start of the file.
You need to test for EOF after reading a byte with fgetc(), otherwise you will output the EOF converted to unsigned char to stdout before exiting the loop.
It is good style to return 0; from main() to indicate success and non-zero to indicate failure.
Here is a corrected version:
#include <stdio.h>
int main(void) {
FILE *fp;
char s[] = "abcdef";
int i, c;
fp = fopen("ot.txt", "w+");
if (fp == NULL) {
printf("file open error\n");
return 1;
}
i = 0;
while (s[i] != '\0') {
fputc(s[i], fp);
i++;
printf("%d", i);
}
rewind(fp);
while ((c1 = fgetc(fp)) != EOF) {
putchar(c1);
}
printf("\n");
fclose(fp);
return 0;
}
What i need to do, is to take a file of n lines, and for every x lines, create a new file with the lines of the original file. An example would be this:
Original File:
stefano
angela
giuseppe
lucrezia
In this case, if x == 2, 3 file would be created, in order:
First file:
stefano
angela
Second FIle:
giuseppe
lucrezia
Third File:
lorenzo
What i've done so far is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
int getlines(FILE *fp)
{
int c = 0;
int ch;
do{
ch = fgetc(fp);
if(ch == '\n')
{
c++;
}
}while(ch != EOF);
fseek(fp, 0 , SEEK_SET);
return c;
}
int ix = 0;
void Split(FILE *fp, FILE **fpo, int step, int lines, int *mem)
{
FILE **fpo2 = NULL;
char * filename = malloc(sizeof(char)*64);
char * ext = ".txt";
char number[2];
for(int i = ix; i < *mem; i++)
{
itoa(i+1, number,10);
strcpy(filename, "temp");
strcat(filename, number);
strcat(filename, ext);
if(!(fpo[i] = fopen(filename, "w")))
{
fprintf(stderr, "Error in writing\n");
exit(EXIT_FAILURE);
}
}
char ch;
int c = 0;
do{
ch = fgetc(fp);
printf("%c", ch);
if(ch == '\n')
{
c++;
}
if(c >= step)
{
c = 0;
ix++;
if(ix >= *mem && (ix*step) <= lines)
{
*mem = *mem + 1;
fpo2 = realloc(fpo, sizeof(FILE*)*(*mem));
Split(fp, fpo2, step, lines, mem);
}
}
putc(ch, fpo[ix]);
}while(ch != EOF);
}
int main()
{
FILE * fp;
if(!(fp = fopen("file.txt", "r")))
{
fprintf(stderr, "Error in opening file\n");
exit(EXIT_FAILURE);
}
int mem = N;
int lines = getlines(fp);
int step = lines/N;
FILE **fpo = malloc(sizeof(FILE *)*N);
Split(fp, fpo, step, lines, &mem);
exit(EXIT_SUCCESS);
}
I'm stack with segmentation error, i couldn't find the bug doing
gdb myprogram
run
bt
I really appreciate any help.
EDIT:
I've changed some things and now it works, but it creates an additional file that contains strange characters. I need to still adjust some things:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
int getlines(FILE *fp)
{
int c = 0;
int ch;
do{
ch = fgetc(fp);
if(ch == '\n')
{
c++;
}
}while(ch != EOF);
fseek(fp, 0 , SEEK_SET);
return c;
}
int ix = 0;
void Split(FILE *fp, FILE **fpo, int step, int lines, int *mem)
{
FILE **fpo2 = NULL;
char * ext = ".txt";
for(int i = ix; i < *mem; i++)
{
char * filename = malloc(sizeof(char)*64);
char * number = malloc(sizeof(char)*64);
itoa(i+1, number,10);
strcpy(filename, "temp");
strcat(filename, number);
strcat(filename, ext);
if(!(fpo[i] = fopen(filename, "w")))
{
fprintf(stderr, "Error in writing\n");
exit(EXIT_FAILURE);
}
free(number);
free(filename);
}
char ch;
int c = 0;
do{
ch = fgetc(fp);
printf("%c", ch);
if(ch == '\n')
{
c++;
}
if(c >= step)
{
c = 0;
ix++;
if(ix >= *mem && ((ix-1)*step) <= lines)
{
*mem = *mem + 1;
fpo2 = realloc(fpo, sizeof(FILE*)*(*mem));
Split(fp, fpo2, step, lines, mem);
}
}
putc(ch, fpo[ix]);
}while(ch != EOF);
}
int main()
{
FILE * fp;
if(!(fp = fopen("file.txt", "r")))
{
fprintf(stderr, "Error in opening file\n");
exit(EXIT_FAILURE);
}
int mem = N;
int lines = getlines(fp);
int step = lines/N;
FILE **fpo = malloc(sizeof(FILE *)*N);
Split(fp, fpo, step, lines, &mem);
exit(EXIT_SUCCESS);
}
There are a few problems in your code. But first I think you need to fix the most important thing
int step = lines/N;
Here step is 0 if your input file has less than N lines of text. This is because lines and N both are integer and integer division is rounding down.
I won't fix your code, but I'll help you with it. Some changes I
suggest:
Instead of getlines, use getline(3) from the standard
library.
fseek(fp, 0 , SEEK_SET) is pointless.
In char * filename = malloc(sizeof(char)*64), note that
both arguments to malloc are constant, and the size is arbitrary.
These days, it's safe to allocate filename buffers statically,
either on the stack or with static: char filename[PATH_MAX].
You'll want to use limits.h to get that constant.
Similarly you have no need to dynamically allocate your FILE
pointers.
Instead of
itoa(i+1, number,10);
strcpy(filename, "temp");
strcat(filename, number);
strcat(filename, ext);
use sprintf(filename, "temp%d%s", i+1, ext)
get familiar with err(3) and friends, for your own convenience.
Finally, your recursive Split is -- how shall we say it? -- a nightmare. Your whole program
should be something like:
open input
while getline input
if nlines % N == 0
create output filename with 1 + n/N
open output
write output
nlines++
I am writing a C program to convert all uppercase characters to lowercase and all lowercase to uppercase from a file.
I also want to count the characters read and the number of characters converted to uppercase and characters converted to lowercase.
I am able to convert the characters but unable to figure out how to count them.
Example;
Hello World!
Output;
hELLO wORLD!
Read 13 characters in total.
8 converted to uppercase.
2 converted to lowercase.
Here's my code;
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define INPUT_FILE "input.txt"
#define OUTPUT_FILE "output.txt"
int main()
{
FILE *inputFile = fopen(INPUT_FILE, "rt");
if (NULL == inputFile) {
printf("ERROR: cannot open the file: %s\n", INPUT_FILE);
return -1;
}
// 2. Open another file
FILE *outputFile = fopen(OUTPUT_FILE, "wt");
if (NULL == inputFile) {
printf("ERROR: cannot open the file: %s\n", OUTPUT_FILE);
return -1;
}
int c;
int ch;
int upper = 0;
int lower = 0;
int count = 0;
while (EOF != (c = fgetc(inputFile))) {
ch = islower(c)? toupper(c) : tolower(c);
fputc(ch, outputFile);
}
while (EOF != (c = fgetc(inputFile))) {
if (isupper(c))
{
upper++;
}
else if (islower(c))
{
lower++;
}
fputc(upper, outputFile);
fputc(lower, outputFile);
}
fclose(inputFile);
fclose(outputFile);
return 0;
}
Your main problem is that you are using 2 loops to read input file.
Your second loop should rewind the file before to start re-reading the file.
You can count and convert with a single loop.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define INPUT_FILE "input.txt"
#define OUTPUT_FILE "output.txt"
int main()
{
FILE *inputFile = fopen(INPUT_FILE, "rt");
if (NULL == inputFile) {
printf("ERROR: cannot open the file: %s\n", INPUT_FILE);
return -1;
}
// 2. Open another file
FILE *outputFile = fopen(OUTPUT_FILE, "w");
if (NULL == outputFile) {
printf("ERROR: cannot open the file: %s\n", OUTPUT_FILE);
return -1;
}
int ch;
int upper = 0;
int lower = 0;
int count = 0;
while (EOF != (ch = fgetc(inputFile)))
{
if (isalpha(ch))
{
if (islower(ch))
{
ch = toupper(ch);
upper++;
}
else
{
ch = tolower(ch);
lower++;
}
count++;
}
fputc(ch, outputFile);
}
fprintf(outputFile, "\nTotal: %d\nToUpper: %d\nToLower: %d\n", count, upper, lower);
fclose(inputFile);
fclose(outputFile);
return 0;
}
Take also note that you have to check if a read char is an alpha char before to convert the case, as the isalpha call inside the loop do.