I am typing a very simple C program which reads characters from a file and displays it "encrypted" by replacing each character with the one 3 characters after (Caesar cipher).
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *inFile;
int ch;
int ch1;
if (argc!= 2){
printf("Usage: Code <inputfile> [> Outfile]\n");
return(-1);
}
inFile = fopen(argv[1], "r");
while ((ch1=toupper(fgetc(inFile)))!='\0') {
ch=ch1;
if (ch >=33 && ch <=255) //exclude special chars
ch += 3;
putchar(ch);
}
printf("END\n");
fclose(inFile);
return 0;
}
I compile it with gcc with gcc encode.c and then run ./a textfile. A line follows with the "encoded" text, then, after 2 seconds, the terminal is filled with garbage, specifically an ascii square. I escape it with Ctrl-C. Obviously the while loop never ends, since I never see the END string. I wondered whether '\0' is the problem and i replaced it with NULL but not only the problem persists, but I also receive a warning during compile.
Related
On numerous sources, you can find a simple C program to count the number of lines in a file. I'm using one of these.
#include <stdio.h>
int main(int argc, char* argv[]) {
FILE *file;
long count_lines = 0;
char chr;
file = fopen(argv[1], "r");
while ((chr = fgetc(file)) != EOF)
{
count_lines += chr == '\n';
}
fclose(file); //close file.
printf("%ld %s\n", count_lines, argv[1]);
return 0;
}
However, it fails to count the num. of lines in Top2Billion-probable-v2.txt. It stops on the line
<F0><EE><E7><E0><EB><E8><FF>
and outputs
1367044 Top2Billion-probable-v2.txt
when it should output 1973218846 lines. wc -l somehow avoids the problem (and is amazingly faster).
Should I give up with a correct C implementation of counting the number of lines of a file or how should I space the special characters as wc does?
fgetc() returns the character read as an unsigned char cast to an int or EOF. Hence declaring chr as int instead of char should solve the issue.
I tried creating a .c program that when it is run it takes a file and it prints only the lines on which there is something (a space, a letter, a number....etc) not the blank lines.
I need to run this on a virtual machine using ubuntu(it's running the newest version of ubuntu). So far I have only managed to print it's contents but not on lines like they are in the file.
The code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char *name = argv[1];
FILE *f = fopen(name, "r");
char x;
while(fscanf(f, "%c" , &x) > 0)
{
printf("%c", x);
if(x == '\n')
{
printf("\n");
}
}
}
file contents:
as
d
3
results:
asd3
desired result:
as
d
3
First, you have no error checking. That makes your program difficult to use.
Second, you output every character unconditionally and then output newlines an extra time. What you want to do is output every character once, unless it's a newline right after a newline (as that would create an empty line) in which case you don't want to output it.
Here's the code fixed up:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf (stderr, "An argument is required\n");
return -1;
}
char *name = argv[1];
FILE *f = fopen(name, "r");
if (f == NULL)
{
fprintf (stderr, "Unable to open file for reading\n");
return -1;
}
char x, px = '\n';
while(fscanf(f, "%c" , &x) > 0)
{
// don't output a newline after a newline
if ((x != '\n') || (px != '\n'))
printf("%c", x);
// keep track of what character was before the next one
px = x;
}
}
It really would be much easier to just read each line in and then output the line if it's non-empty.
You can use fgets() function which gets the entire line including the new line character (\n), After you read the line, you can skip printing the line if the first character (line[0]) is newline character.
Here is the code segment that does it, You need to error checking for argc and file existence as done by #David Schwartz
char line[200];
while (fgets(line, 100, fp))
{
if (line[0] != '\n')
printf(line);
}
This should work.
When I try to read input from a file named "file1", my program correctly displays
the number of characters in the file, but in an unrecognized character format.
Below is the code
#include <stdio.h>
#include <stdlib.h>
void db_sp(FILE*);
int main(int argc,char *argv[])
{
FILE *ifp,*ofp;
if(argc!=2) {
fprintf(stderr,"Program execution form: %s infile\n",argv[0]);
exit(1);
}
ifp=fopen(argv[1],"r");
if (ifp==NULL) printf("sdaf");
//ofp=fopen(argv[2],"w+") ;
db_sp(ifp);
fclose(ifp);
//fclose(ofp);
return 0;
}
void db_sp(FILE *ifp)
{
char c;
while(c=getc(ifp) !=EOF) {
//printf("%c",c);
putc(c,stdout);
if(c=='\n' || c=='\t' || c==' ')
printf("%c",c);
}
}
The problem is here:
while(c=getc(ifp) !=EOF){
Because of operator precendence, this getc(ifp) !=EOF gets executed first. Then c = <result of comparison> gets executed. Which is not the order you want.
Use parentheses to force the correct order.
while((c=getc(ifp)) !=EOF) {
Other notes:
getc returns an int so you should change the type of c to int.
Also, if you fail to open the file, you still continue execution. You should gracefully exit on failure.
Look here, those two programms should be equivalent in my opinion. But obviously they aren't, as the first programm works and the second doesn't. Can someone explain to me, why fgets() doesn't do the job?
// FIRST PROGRAM : WORKS FINE
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char fileName[67];
scanf("%s", fileName);
printf("%s", fileName);
stream = fopen(fileName, "r");
char ch;
if(stream){
ch = fgetc(stream);
while(!feof(stream)){
putchar(ch);
ch = fgetc(stream);
}
fclose(stream);
}
}
// SECOND PROGRAM: DOES NOT WORK
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char fileName[67];
fgets(fileName, 67, stdin);
printf("%s", fileName);
stream = fopen(fileName, "r");
char ch;
if(stream){
ch = fgetc(stream);
while(!feof(stream)){
putchar(ch);
ch = fgetc(stream);
}
fclose(stream);
}
}
I enter "test.txt" into the console both times and press enter then. Of course test.txt exists in the right directory
The reason is that fgets() retains the newline entered. You can verify it is there by altering your print statement to
printf("[%s]", filename);
when the ] will appear on the next line. You can remove the trailing newline like this
#include <string.h>
...
filename [ strcspn(filename, "\r\n") ] = 0;
The main problem you experienced is correctly solved by Weather Vane, but I want to point another problem with your code: the loops for reading and writing the contents of the file are incorrect. Testing the end of file with feof(stream) leads to incorrect behaviour most of the time. In your case, a read error from stream will cause your program to loop endlessly, writing 0xFF bytes to stdout.
There is a much simpler and idiomatic way to implement this loop:
if (stream) {
int ch;
while ((ch = fgetc(stream)) != EOF) {
putchar(ch);
}
fclose(stream);
}
As you can see, it is simpler and correctly tests for EOF at the right time, when input fails. It stores the return value of fgetc() into an int variable capable of holding all possible return values from fgetc(). Using an int is necessary because comparing a char value to EOF either always fails if the char type is unsigned or potentially gives false positives if char is signed and has value '\377'.
I'm trying to get input from the user in the console, but I'm having problems with the function getline() in my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <memory.h>
#include <sys/wait.h>
#include <errno.h>
int main(int argc, char *argv[])
{
//check that the number of arguments given is valid
if (argc != 2){
printf("Error: arguments. \nThe file should only take one argument which is the name of the level\n");
exit(1);
}
char test[5];
int nb_lettres=strlen(argv[1]);
strncpy(test,argv[1]+nb_lettres-4,4);
//check that the file given is either a .tgz or a .tar
test[4]='\0';
if(strcmp(test,".tar")!=0 && strcmp(test,".tgz")!=0)
{
printf("Error: arguments. \nThe argument should be a file having the extension .tar or .tgz \n");
exit(2);
}
int status; //START OF THE PART CONTAINING THE PROBLEM
pid_t pid;
//create the folder then move to it, then extract the tar
if((pid=fork())!=0){
if(fork()){
execlp("mkdir","mkdir","leaSHdir",NULL);
}
//waiting to make sure we don't try to go in the folder before it's fully created
wait(&status);
execlp("tar","tar", "-xf", argv[1], "-C", "leaSHdir/",NULL);
}
waitpid(pid,&status,0);
printf("Extracting the files..\n");
sleep(1); //END OF THE PART CONTAINING THE PROBLEM
//Read the meta file
FILE *file;
chdir("./leaSHdir");
file=fopen("meta","r");
if (file==NULL){
// printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
printf("Error: meta. \nImpossible to read the meta file. Please check that it does exist (without looking in, vile cheater)\n");
exit(3);
}
char *line=NULL;
size_t len=0;
//Saving the commands which will be used by the user
char *result=NULL;
char **commands = malloc(5 * sizeof *commands);
int i=0;
if(commands==NULL){
printf("Error: memory. \nA problem occured with the memory while creating a pointer\n");
exit(4);
}
while(getline(&line,&len,file)!=-1){
if(strstr(line,"$")!=NULL){
commands[i]=(malloc(strlen(line)));
strcpy(commands[i],line+2);
//if the array is full,we add space for the next incoming command
if(i >= 4){
commands=realloc(commands,sizeof *commands *(i+2));
}
i++;
}
if(line[0]=='>'){
result=malloc(strlen(line));
strcpy(result,line+2);
}
}
int a = 0;
for (a = 0;a<i;a++){
printf("%s",commands[a]);
}
printf("%s",result);
printf("Erasing meta..");
unlink("meta");
printf("meta erased.\n");
int c;
while((c = getchar()) != '\n' && c != EOF){
printf("rien\n");
}
ssize_t r = getline(&line,&len,stdin);
printf("%d '%s' %d",(int) r, line, c);
char machin[2555];
scanf("%s",machin);
printf("%s test",machin);
free(commands);
free(result);
return 0;
}
When I execute this code, the last getline is completely skipped (the first one is working without any problem), which I don't see why. I've also tried using different functions (fgets, scanf) and both were also skipped.
Thanks in advance for any help which can be provided :)
Edit:
Changed the faulty getline line with ssize_t r = getline(&line,&len,stdin); printf("%d '%s' %d",(int) r, line, c);, here's the result:
cat
ls
man
Bravo! C'est ici!//this line and the 3 other lines before are the lines read by the first getline which is working
Erasing meta..meta erased.
-1 '> Bravo! C'est ici!
' -1
So basically, I don't even have time to type anything, I get this result directly without entering anything. Also the content of line isn't changed after the second getline considering it still contains the result from the first getline.
Edit 2 :
Okay, I think I found from where comes the problem: Basically, it's from a part of the code i didn't put in the extract there because I though it was not related at all with my current problem, so I've edited the whole extract to put it fully. I've put two comments to mark the part containing the problem. Although I don't see what could be causing it, considering this part contains only forks.
Although, sorry for the trouble, guys, should have put the whole code at the start
Last edit:
Figured out what was the problem: if((pid=fork())!=0){ which means that once my forks ended I was working on the child process and not on the father as I thought. Once I've changed it to if((pid=fork())==0){ everything worked fine. Thanks for the help :)
[Edit]
After some edits:
OP's problem occurs when using stdin after fork().
Similar to Two processes reading the same stdin
Code is unable to take in additional input as stdin has all ready reached the EOF condition or a rare IO error. That is the -1 return values from getline() and getchar(). line simply retains its former contents as nothing was changed.
char c;
while((c = getchar()) != '\n' && c != EOF);
ssize_t r = getline(&line,&len,stdin); //getline not working
printf("%d '%s' %d",(int) r, line, c);
-1 '> Bravo! C'est ici!
' -1
Additional issue: realloc() too late.
strcpy(commands[5],line+2); writes to unallocated memory.
char **commands=malloc(sizeof(char**)*5);
int i=0;
...
// In loop, i becomes 5.
...
strcpy(commands[i],line+2);
if (i > 5){
commands=realloc(commands,sizeof(char**)*(i+2));
Put somtehing before getilne to consume the trailing '\n' character. For example:
while ( getchar() != '\n' );
getline(&line,&len,stdin);