input redirection on CMD - c

Well, I am learning programming in C, and I got an assignment to get 3 characters from an input text file into 3 variables and then print their ASCII values.
I wrote this code:
#include <stdio.h>
int main()
{
char a,b,c;
printf("Insert 3 characters:\n");
a=getch();
b=getch();
c=getch();
printf("%d, %d, %d",(int)a,(int)b,(int)c);
}
I opened a text file (input.txt) and wrote there: "abc".
I managed to compile the code with the MinGW compiler, and on the CMD window that I opened in the folder of the .exe file, I wrote: "Task.exe <input.txt".
The program ran normally. I mean, it waited for me to input 3 characters.
What have I done wrong in my work?
help me please :)

You are asked to read from an input text file.
Why don't you use fopen to open a file handle, and fgetc to read from it?
You could perhaps use fscanf. Don't forget to use the resulting count.
And of course, you should call fclose. Using perror is useful to handle error cases.
So start your code with something that checks that your program has an argument, then fopen it:
int main(int argc, char**argv) {
if (argc<2) { fprintf(stderr, "missing program argument\n");
exit(EXIT_FAILURE); };
FILE* fil = fopen(argv[1], "r");
if (!fil) { perror(argv[1]); exit(EXIT_FAILURE); };
Then run Task.exe input.txt in your console (no redirection needed!).
You should take the habit of reading the documentation of every function you are using, of testing failure cases, of compiling with all warnings & debug info (gcc -Wall -Wextra -std=c99 -g), and of using the debugger (gdb).

Related

A question about allocating memory : C [UBUNTU]

I'm currently doing an exercise where I have to create a program that takes all the code that is written inside it, and outputs it to the screen when the program is executed.
The exercise suggests that we may find it appropriate to change the file names of the program in the future - and assuming that the renaming is done in a coordinated manner, i.e. the source file and the execution file are given the same new name (except for the extension), the program should work correctly, without the need for any changes to the source code, and without the need to recompile.
The C program itself is called 'prnt.c'-
I wrote the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ENDFILEC ".c" /* extension */
int main(int argc, char *argv[])
{
FILE *filePointer;
int character;
char *fileNameToOpen;
fileNameToOpen = (char *)malloc(strlen(argv[0]) + 3); /* allocating memory for string + 3 for the extension - '.c' and \0 */
strcpy(fileNameToOpen, argv[0]);
strcat(fileNameToOpen , ENDFILEC); /* ending '.c' in the end */
filePointer = fopen(fileNameToOpen, "r");
while(!feof(filePointer))
{
character = fgetc(filePointer);
printf("%c" , character);
}
fclose(filePointer);
return 0;
}
I made a 'makefile' to compile the program and I made it so that the executable would be called 'prnt1'.
basically, like the following:
prnt1 : prnt.c
gcc -ansi -Wall -pedantic prnt.c -o prnt1
The compilation worked, but whenever I run the program itself, it gives me a runtime error, saying: "Segmentation fault (core dumped)". When I look at the code itself, I don't seem to reach a memory that doesn't belong to me, so what could be an explanation for that problem and what can be done about it? Thank you in advance for your help.
Since you said that the executable is named "prnt1" and the source file (which you want to read the code from) is named "prnt", argv[0] has the name of the executable (i.e. "prnt1") and, when ".c" is appended to argv[0], it becomes "prnt1.c" – which is definitely not the file you are trying to read from; athen, since this file doesn't exist, you're getting a segmentation fault.
So, as Tom Karzes said, always check the return value of fopen().

How to get fscanf to scan the next Line in C

The text file is a list of words similar to this. each world is on a new line
When i run my code, the only thing being printed is "hi".... how do i get it to continue to read the next lines
hi
hello
welcome
#include <stdio.h>
#include <stdlib.h>
int main()
{
char data[100];
// OPENS THE FILE
FILE *fp = fopen("/classes/cs3304/cs330432/Programs/StringerTest/people.txt", "r");
if (fp == NULL)
{
printf("Unable to open the file\n");
} else {
fscanf(fp, "%s", data);
printf("%s", data);
fclose(fp);
}
}
How to get fscanf to scan the next Line in C
Read the documentation of fscanf. You cannot scan lines with it. And fscanf can fail, and you should handle its failure.
A possible approach is to read the next line using fgets (or getline, or readline) and later to parse it using sscanf.
Be also aware that in 2021, UTF-8 is used everywhere. So document on paper what your program should do if your people.txt file contains a line like Être ou ne pas être or a line with СТАРЫНКЕВИЧ (in Cyrillic letters).
If allowed, use a recent GCC compiler as gcc -Wall -Wextra -g (asking for all warnings and debug info), improve your code to get no warnings, and then use the GDB debugger to understand the behavior of your program. You could install Debian on your laptop to get gcc and gdb
The documentation of your program could use EBNF notation to specify what are the valid inputs.
Consider generating parts of your C code with tools like GNU bison.
When fopen fails you could use perror to report the error.
You may want to read the wikipage about recursive descent parsing.
You may want to study -for inspiration- the source code of GNU coreutils.

system() function doesn't produce expected output file

F
I'm using Graphviz to render .dot file as graphs, and typically I would write in my terminal :
dot -Tpng yourFile.dot -o yourOutput.png to produce a .png image representing my graph. (I'm using a Unix environment btw)
Now let's say I have the following C function:
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 255
typedef struct placeholder mystruct;
struct placeholder {
...
}
void outputGraph(mystruct str, char* outputName) {
char command[MAXSIZE];
char* tmpFile = "temp.dot";
char imageFile[MAXSIZE];
snprintf(imageFile, MAXSIZE, "%s.png", outputName);
FILE* file = fopen(tmpFile, "w");
writeStructToFile(str, file);
snprintf(command, MAXSIZE, "dot -Tpng %s -o %s", tmpFile, imageFile);
system(command);
snprintf(command, MAXSIZE, "rm %s", tmpFile);
system(command);
}
(my function WriteStructToFile is another one that I made and is working properly so the problem is somewhere else)
From what I understood about the system() function, it should produce the image output just the same as when I execute the same command myself.
Well, it does execute without any errors, but there is no image in the directory where I'm working.
At first, I thought, it's easy, system() doesn't start a new shell in the same working directory, so I tried to see the output of system(pwd); and it was my current working directory. So back to the starting point.
I also tried to check the value system(command) by doing int status = system(command); and then printf("status : %d\n", status); and, well, it printed 0.
Now I'm kinda clueless, I really don't see why it doesn't produce the image output.
I'd be very interested in any ideas or even solutions you have.
This is not the most elegant code, but it works & may help you debug your problem. It calls dot in three different ways. All three work as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
char command[50];
int rc;
strcpy(command, "dot -Tdot this.gv" );
rc=system(command);
printf("\n\n+++ call #1 returned %d\n", rc);
strcpy(command, "dot -Tdot this.gv -oout1.dot" );
rc=system(command);
printf("\n\n+++ call #2 returned %d\n", rc);
strcpy(command, "dot -Tdot this.gv -o out2.dot" );
rc=system(command);
printf("\n\n+++ call #3 returned %d\n", rc);
return(0);
}
snprintf(command, MAXSIZE, "touch %s", tmpFile);
system(command);
Why do you code that?
You certainly don't need to use system(3) then touch(1). You could use appropriate syscalls(2) (open(2) and close(2) here) or at least fopen(3) followed by fclose(3).
You might in some cases consider using popen(3) with pclose(3)
Of course, after
snprintf(command, MAXSIZE, "dot -Tpng %s -o %s", tmpFile, imageFile);
int bad = system(command);
You need to first check that bad is 0 and you probably want to use stat(2) or access(2) to check that imageFile exists.
There could be many reasons why system with a dot command fails. For example, a bad $PATH variable. I suggest using popen(3) with pclose(3) and probably /usr/bin/dot in the command.
Compile your C code using GCC as gcc -Wall -Wextra -g and use GDB to debug your executable. Both strace(1) and ltrace(1) could help you understand the behavior of your program.
Consider reading Advanced Linux Programming and studying for inspiration the source code of some simple open source Linux shells, such as sash or (more complex) GNU bash.
Be aware that Graphviz could be used as a library.
I wasn't closing the temp.dot file in which I was writing. My mistake.
I shall now remember to always close files that I open!
A big thank you to everyone who helped on here.
(Whether it was for the problem or on how to use properly SO)

Execute hello.c file by using file handlers in C

I'm trying my luck with C lately and I came across to this question where I'm stuck.
I've a hello.c file
CODE 1
#include<stdio.h>
#include<stdlib.h>
int main(){
printf("Hello World");
return 0;
}
I open this file and display the content using the following C program (CODE 2)
CODE 2
#include<fcntl.h>
#include<stdio.h>
int main() {
FILE *fd;
char ch;
fd = fopen("/home/hello.c","r");
if( fd != NULL ) {
while((ch = getc( fd )) != EOF){
putchar(ch);
}
}
return 0;
}
However, I want the output of this code to be Hello World, i.e output of the hello.c file which is read.
How can that be done?
In order to run a c file, first you need to compile it into machine code then execute it.
To compile it: run gcc source-file -o executable-file
To run, execute: executable-file
In order to to the same things in C, use system() function from <stdlib.h>
const char* tempFile = "./tempfile";
const char* sourceFile = "hello.c";
const char compileCommand[255];
sprintf(compileCommand, "gcc %s -o %s", sourceFile, tempFile);
system(compileCommand);
system(tempFile);
This code hasn't been tested.
Currently, in the second program, you are reading hello.c file. So the output of CODE2 will be the contents of hello.c. i.e. #include<stdio.h>...
For what you need, in CODE1, you need to write the output of the program into a separate file (say a.txt) and then read a.txt in CODE2.
Hope this is a sufficient hint for you to solve further.
Your "CODE 2" would have to invoke a C-compiler to compile "CODE 1" and then run it using system() or a function provided by your operating system.
BTW: It is either int main(void) or int main(int argc, char** argv), NOT int main().
As general solution, you may try also to have a look to a C interpreter, like Cling, and try to include it in your project.

fopen() and command line arguments

I'm trying to write a program that will read the first character in a text file. If I use ./a.out myfile.txt it works as intended but if I use ./a.out <myfile.txt I get Segmentation fault: 11. The reason why I'm trying to include the <is because this what is in the spec of the assignment. The below code is just a simplified example that i've made that has the same issue:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int func(int argc, char **argv){
FILE *fp;
int test = 0;
fp = fopen(argv[1], "r");
fscanf(fp, "%i", &test);
printf( "current file: %s \n", argv[1]);
}
int main(int argc, char **argv){
func(argc, argv);
}
Is there any way I can get it to accept the argument as <myfile.txt?
No, nor should you try. Files redirected this way will appear at stdin and you should use that instead (hint: check argc).
If you want to use a file if specified, but otherwise stdin, use something like:
if (argc > 1)
fp = fopen(argv[1], "r");
else
fp = stdin;
In your command ./a.out <myfile you redirect stdin to myfile. This means reading from stdin is actually reading from myfile. So, in this case your argc == 1, so argv[1] you use to open is NULL (see main spec on its arguments). fopen crashes when uses NULL name.
You may do your utility in another way: always read stdin. When you need file to input do like this: cat myfile | ./a.out. This is very nice approach and worth considering.

Resources