I have to develop a program in C that can have two kinds of inputs.
By feeding it a string ( I am assuming like this filename < String1234455678, please correct me if I am wrong).
By reading data from some file(s).
I have to do some checks regarding the characters that are in it and store them in an array. But I want to learn how to use the getc() from stdin first.
My first question is, can I use getc() in both cases?
I wanted to loop through every single character in the feed line/file, and I assume the code would look something like this:
char Array1[];
char charHolder;
//If the file/feed has chars (!NULL), execute
if ((charHolder = getchar())!=NULL){
//Do something
//Do some more
//Finally append to Array1
Array1[] = charHolder;
}
There might be some issues with the code above. I wanted to know if that kind of inserting is valid in C (with no index specified, which it will just push the value at the end of the array). Also, I read from http://beej.us/guide/bgc/output/html/multipage/getc.html that getc(stdin) and getchar() are exactly equivalent. I just want to double check that this is indeed true and either function will work with both my cases where I have to read data (from a file and feeding my program a string).
Also, I was wondering how I can achieve reading characters from multiple files. Say if my program was to be executed as programName file1 file2.
Thank you for your time and help!
Cheers!
Edit 1:
I also wanted to know how to check when the chars end from a file/string feed. Should I use the EOF for both cases?
Example:
while ((charHolder = getchar()) != EOF){
//code
}
Here is a sample:
#include <stdio.h>
void do_read(FILE * file, int abort_on_newline) {
char ch;
while (1) {
ch = getc(file);
if (ch == EOF) {
break;
}
if (abort_on_newline && ch == '\n') {
break;
}
printf("%c", ch);
}
}
int main(int argc, char * argv[])
{
int i = 1;
FILE * fp = NULL;
if (1 == argc) {
// read input string from stdin, abort on new line (in case of interactive input)
do_read (stdin, 1);
}
else {
// cycle through all files in command line arguments and read them
for (i=1; i < argc; i++) {
if ((fp = fopen(argv[i], "r")) == NULL) {
printf("Failed to open file.\n");
}
else {
do_read(fp,0);
fclose(fp);
}
}
}
return 0;
}
Use it like this:
To read from stdin: echo youstring | youprogram, or just start
yourprogram to get input from user
To read from file(s) yourprogram yourfile1 yourfile2 ...
Yes your can use getc in both cases, yes you should check for EOF in both cases, except for interactiv input. In case of binary files you also need to use feof function to check for EOF. See code above to read from multiple files.
Related
I am working in Unix and I am supposed to first read in text through redirection and then ask the user to enter in a specific character and count how many times it is in the character array.
const int MAX = 8000;
int input = 1;
int i = 0;
char text[MAX], letter;
while(input != 0)
{
scanf("%c", &text[i]);
if(text[i] == '0')
input = 0;
i++;
}
printf("\n%s",text);
printf("\nEnter a letter to search for in the text: ");
scanf("%c", &letter)
Currently, I am printing the correct file through redirection, however my second scanf is being skipped. I am redirecting the file using the command: ./a.out < filename.txt.
If I try and print the character letter then it will result in nothing. It must be reading the \n from inside the empty lines of the text file still. How do I stop the scanf from reading the same text file and let me enter a letter from my keyboard in the console? As an assignment I HAVE to use the command ./a.out < filename.txt.
The freopen() function is exactly what you're looking for. You just need to use it to (re)open /dev/tty as stdin. /dev/tty is a special file referring to the terminal that started the program.
From the manual page:
The freopen() function opens the file whose name is the string pointed to by pathname and associates the stream pointed to by stream with it. The original stream (if it exists) is closed. The mode argument is used just as in the fopen() function.
[...]
The primary use of the freopen() function is to change the file associated with a standard text stream (stderr, stdin, or stdout).
Here's an example:
// ...
FILE *tty;
tty = freopen("/dev/tty", "r", stdin);
if (tty == NULL) {
perror("Unable to open terminal for reading");
exit(1);
}
printf("Enter a letter to search for in the text: ");
// Now scanf will read from the console where the process started.
scanf("%c", &letter);
By the way, your program has some issues. You could read past the end of your text array, you don't correctly terminate it with a NUL character, and you also don't check for errors. A more correct version would be:
const size_t MAX = 8000;
char text[MAX];
size_t i;
int c;
for (i = 0; i < MAX; i++)
{
c = fgetc(stdin);
if (c == EOF)
break;
text[i] = (char)c;
}
text[i] = '\0';
puts(text);
There are a few ways to do this, probably the easiest is just to open /dev/tty which is a special device referring the terminal attached to the current process. I don't recommend replacing stdin as then you will lose access to your file which is redirected there. Instead just use a different file pointer and use functions like fscanf and fgetc. Eg:
FILE *tty = fopen("/dev/tty", "r");
// fopen will return NULL if there is no attached terminal
if(NULL == tty)
{
fputs("Failed opening /dev/tty", stderr);
}
else
{
printf("\nEnter a letter to search for in the text: ");
// Read a character from the terminal
char search = fgetc(tty);
// Now you can still read from the file on stdin and search for
// your letter without needing an array (which may not be large
// enough for the whole file)
char ch;
int count = 0;
while(EOF != (ch = getchar())
{
if(ch == search)
++count;
}
printf("%d occurrences of %c\n", count, search);
}
For more information on /dev/tty and other similar special files, see: https://unix.stackexchange.com/questions/60641/linux-difference-between-dev-console-dev-tty-and-dev-tty0
So I want to make kind of an encryption program for a school project,I want for example the letter 'a' to be replaced with:12345 'b' with 54321 in C,how can I accomplish this?I'm not the best,my code so far:
eFile = fopen("Message.txt", "ab+");
while(!feof(eFile))
{
fscanf(eFile,"%c",&message);
}
I want for example if I write the word apple into the text file,make the program scan it letter by letter and replace every letter with a 5 digit number(I have them predefined already) example: apple = 12342 69865 69865 31238 43297
read character by character from input
use simple array to convert between character to number or to string, or use a handler function for that
print that number
replacing is not easy, simplest way is to create a tempfile, write numbers to that tempfile, than copy the tempfile to the original file and remove tempfile.
_
#include <stdio.h>
#include <assert.h>
int cipher_table[255] = {
['a'] = 12342,
['p'] = 69865,
['l'] = 31238,
['e'] = 43297,
// so on...
};
int main()
{
FILE *fin = stdin; // fopen(..., "r");
assert(fin != NULL);
FILE *fout = stdout; // tmpfile();
assert(fout != NULL);
for (int c; (c = getc(fin)) != EOF;) {
if (c == '\n') {
if (fputc('\n', fout) == EOF) {
fprintf(stderr, "Error writing to file fout with fputc\n");
return -1;
}
continue;
}
if (fprintf(fout, "%5d ", cipher_table[c]) < 0) {
fprintf(stderr, "Error writing to file fout with fprintf\n");
return -1;
}
}
close(fin);
close(fout);
return 0;
}
I'm not sure if your strategy can be called encryption, but it can be easily accomplished
with a lookup table.
Simply put the replacements in an int table like so:
int map[]={ //size will be autoinferred to fit the indices
['a']=12342,
['p']=69865,
['l']=31238,
['e']=43297,
//you should preferrably have an entry for each value of char
};
And use it to print the replacements.
int c;
while(EOF!=(c=fgetc(inputFile)))
if(0>(outPutfile,"%d \n", map[c]))
return -1;
Since the size of the new file will unpredictably change, it'd probably
be a good idea to output into a temporary file and then move it in the
place of the original after it's successfully finished.
A better idea might be to simply forget about in-place file rewriting
and simply read stdin and write to stdout – that would allow the program to handle streams well as well and a possibly wrapper script could turn it into an inplace translator (via the temp file) after the fact if needed.
So both the code to print the lines from the txt file and the code to count the lines in the txt file work fine when the other is commented out but when i try to have both work only the code that comes first works e.g. if i put the code to print out the lines first, the line count is always zero. However if i put the code to count the lines first, the number is correct but the lines from the txt file are not printed :S
#include <stdio.h>
int main(int argc, char const *argv[])
{
const int SIZE = 128;
char line[SIZE];
FILE *srcFile;
int c;
int count = 0; // Line counter (result)
if (argc == 1)
{
printf("No command line arguments given!\n");
return 1;
}
srcFile = fopen(argv[1], "r");
if (srcFile == NULL)
{
perror("\n*** FILE OPEN FAILED ***");
}
else
{
printf("\n*** FILE OPEN SUCCESSFUL ***\n\n");
}
while(fgets(line, SIZE, srcFile) != NULL)
{
printf("%s", line);
}
for (c = fgetc(srcFile); c != EOF; c = fgetc(srcFile))
{
if (c == '\n')
{
count ++;
}
}
if(c != '\n' && count != 0)
{
count ++;
}
printf("The file %s has %d lines\n ", argv[1], count);
fclose(srcFile);
return 0;
}
Here is a quick overview of how working with files is done in most programming languages:
When you open a file in a program you obtain a handle to that file. What the handle representation is depends on the language. In c it is the FILE structure. The handle contains - among other things - a file position indicator. Every read and write to that file through this handle happens at that position. Usually a read/write operation advances this file position indicator. Think about it: how do consecutive reads know to each read where the previous one left? You don't provide an argument to the read function telling it where to read from. You just "say" read. What happens is that each read call reads at the file position indicator and then advances this indicator, thus when the next read happens the handle has an updated file position indicator.
So the solution to your problem is - as mentioned in the comments - to put this position indicator to the beginning of the file. In c this can be done with rewind.
curious how the code fragment would have to look to include the line
count int the same loop as the print lines
Simple. Pseudocode:
line_count = 0
while (read line successful)
{
print line
increment line_count
}
print line_count
The code is supposed to read a user-inputted text file name, copy every character into a multidimensional array, then display it with standard output. It compiles, but produces unintelligible text. Am I missing something?
for (i = 0; i < BIGGEST; i++) {
for (j = 0; j < BIGGESTL; j++) {
if (fgetc(array, fp) ) != EOF)
array[i][j] = c;
else array[i][j] = '\0'
}
fclose(fp);
return 0;
}
You stop filling the array when you encounter EOF, but you print the full array out no matter what.
If the data read from the file is smaller than the input array, you will read that data in and then print that data out, plus whatever random characters were in the memory locations that you do not overwrite with data from the file.
Since the requirement seems to be to print text data, you could insert a special marker in the array (e.g. '\0') to indicate the position where you encountered EOF, and stop displaying data when you reach that marker.
You had better read each line from file
For example:
int i = 0;
while(fgets(text[i],1000,fp))
{
i++;
}
Though the question is edited and only part of the code is left in question. I am posting more than what is required for the question at the moment.
Reason being, there can be numberous improvements to originally posted full code.
In main() function:
You need to check for the argc value to be equal to 2 for your purpose and only then read in value of argv[1] . Else if program executed without the command-line-argument which is file_name in this case, invalid memory read occurs, resulting in segmentation fault if you read in argv[1].
In read_file_and_show_the contents() function:
Stop reading file if end of file is reached or maximum characters is read and store in the character array.
Below Program will help you visualize:
#include <stdio.h>
/*Max number of characters to be read/write from file*/
#define MAX_CHAR_FOR_FILE_OPERATION 1000000
int read_and_show_the_file(char *filename)
{
FILE *fp;
char text[MAX_CHAR_FOR_FILE_OPERATION];
int i;
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("File Pointer is invalid\n");
return -1;
}
//Ensure array write starts from beginning
i = 0;
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while( (fgets(&text[i++],sizeof(char)+1,fp) != NULL) && (i<MAX_CHAR_FOR_FILE_OPERATION) ) ;
//Ensure array read starts from beginning
i = 0;
while((text[i] != '\0') && (i<MAX_CHAR_FOR_FILE_OPERATION) )
{
printf("%c",text[i++]);
}
fclose(fp);
return 0;
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Execute the program along with file name to be read and printed. \n\
\rFormat : \"%s <file-name>\"\n",argv[0]);
return -1;
}
char *filename = argv[1];
if( (read_and_show_the_file(filename)) == 0)
{
printf("File Read and Print to stdout is successful\n");
}
return 0;
}
I have designed a parser with some state transitions. Now i want to redirect a file into my parser created in C to give the tokens.
My design is such that I need a space(' ') at the end of my string, that is , I need to append a space character to the string read from the file or stdin. But the problem is the indexing.
For redirecting from a file i need to do
int length=0;
while((c1=getchar())!=EOF)
{
a[length]=c1;
length ++;
}
a[length-1]=' ';
a[length]=EOF;
While for reading from stdin, i need to do
int length=0;
while((c1=getchar())!=EOF)
{
a[length]=c1;
length ++;
}
a[length]=' ';
a[length+1]=EOF;
The input can come both from a stdin input or a file redirection(eg ./a.out < a.c) Now how do I do incorporate if these in my code, based on the type of input???
First off, both cat data | ./a.out and ./a.out < data produce exactly the same effect, namely that the program's stdin reads the file.
Perhaps what you want is a syntax like ./a.out data. For this, I'd suggest a loop like this:
void process_my_data(FILE *); // main logic here!
int main(int argc, char * argv[])
{
if (argc == 1)
{
process_my_data(stdin);
}
else
{
while (--argc)
{
FILE * f = fopen(argv[argc], "rb");
process_my_data(f);
fclose(f);
}
}
}