int main(int argc,char *argv[])
{
int f1,flag,n;
if(argc<3)
{
printf("Correct format: ./a.out <fileName> <string>\n");
exit(-1);
}
f1=creat(argv[1],0666);
if(f1<0)
{
printf("Creatioon error\n");
exit(f1);
}
n=strlen(argv[2]);
printf("%d\n",n);
while(n-->0)
flag=write(f1,argv[2]++,1);
if(flag<0)
{
printf("Write error\n");
exit(flag);
}
close(f1);
return 0;
}
here in flag=write(f1,argv[2]++,1); why do we do argv[2]++ and why is the length of the text to be copied is 1??
The increment is because it's in a (stupid) loop:
while(n-->0)
flag=write(f1,argv[2]++,1);
but your code isn't indented so it's a bit harder to see.
argv[2] is a char * pointing at the string entered as the third word on the command-line, so incrementing it steps it to the next character in the string.
This is bad code; it should be write(fl, argv[2], n); to write it all at once. Of course, the return value must still be inspected and the write() maybe looped to try again or resume if there is a partial write.
The length is 1 because the 3rd argument of write is 1.
You probably want this:
/* write second command line argument to the file */
flag=write(f1, argv[2], strlen(argv[2]);
Related
I am a beginner in c so I have a problem with get the user to input last name, a comma & then first name. However it will pass to the function call
int get_name(FILE *fp)
in my main function. I have a problem either if I have to use the arguments parameters.
Example, main (int argc, char *argv[])) or just main (void))
and from what I have been searching so far, FILE*fp cannot get the user to enter from stdin it only use to open the file(?) BUT I am required to get the user to input from keyboard and pass to the function. I have written some codes. but they don't seem to work but I am going to put down on here the one I am sure that I need a few changes most.
#define LINESIZE1024
int main(void){
FILE *fp;
char line[LINESIZE];
char first;
char last;
char comma;
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(fp = (sscanf(line,"%s %s %s",&last,&comma,&first)==3))
get_name(fp);
if(get_last_first(fp)== -1)
break;
printf("Please enter first name a comma and then last name");
}
BUT I got an error saying I can't use pass it from pointer to an integer. and many MORE but I accidentally closed my concolse and all the errors that appeared while I was trying to fix are gone. So please give me some ideas.
What about seconde code
while(1){
if(!fgets(line,LINESIZE,fp)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s %s %s",last,comma,first)==3)
get_last_first(fp);
return 0;
}
It gave me errors too. fp,last,first,comma used uninitialized in this function
OK so I think I have fixed the previous problem now. However it doesn't print the name back if the name is given correctly. Here is my fixed main code.
int main(void){
FILE *fp = stdin;
char line[LINESIZE];
char first[16];
char last[16];
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s ,%s",last,first)==2)
if(get_name(fp)==2)
printf("Your name is: %s %s\n", first, last);
}
return 0;
}
here is my function.
int get_name(FILE *fp){
char line[LINESIZE];
char last[16], first[16];
int n;
/* returns -1 if the input is not in the correct format
or the name is not valid */
if(fgets(line, LINESIZE, fp) == NULL) {
return -1;
}
/* returns 0 on EOF */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == EOF) {
return 0;
}
/* prints the name if it's valid */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == 2) {
return 2;
}
return 1;
}
I thank you people so much for taking time to read and help me. Please don't be mean :)
Seems that you are making it more complicated than needed. Don't call fgets and scanf in main. Only do that in the function get_name.
It can be something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINESIZE 1024
int get_name(FILE *fp)
{
char line[LINESIZE];
char* t;
if(!fgets(line, LINESIZE,fp))
{
printf("Error reading input\n");
return 0;
}
t = strstr(line, ",");
if (t)
{
*t = '\0';
++t;
printf("First: %s - Last: %s\n", line, t);
return 2;
}
printf("Illegal input\n");
return 0;
}
int main(int argc, char **argv)
{
get_name(stdin);
return 0;
}
If you later decide that you want to read from a file, you can reuse the function get_name without changing it at all. All you need is to change main. Like:
int main(int argc, char **argv)
{
FILE* f = fopen("test.txt", "r");
if (f)
{
get_name(f);
fclose(f);
}
else
{
printf("Open file failed\n");
}
return 0;
}
If you want to read from the keyboard, read from stdin or use scanf, which internally reads from stdin. If you want to read from a file instead, use FILE *fp, but don't forget to open the file and check if it was successful (you'll find lots of tutorials for this).
Further, when reading in strings, you need an array of characters, not a single one. Note further, that scanf can already deal with formats like "everything that is not a ',' then a ',' then a string. Note that format "[^,]" means "any character except a ',':
So you could adapt the code as follows:
#define LINESIZE 1024
int main(void){
char line[LINESIZE];
char first[LINESIZE];
char last[LINESIZE];
while(fgets(line,LINESIZE,stdin)) {
if(sscanf(line,"%[^,],%s",last,first)==2) {
printf("Read in %s ... %s\n",last,first);
}
else {
printf("Please enter first name a comma and then last name");
}
}
return 0;
}
And if your professor is picky concerning the "use FILE*", you could write:
FILE *fp = stdin;
...
while(fgets(line,LINESIZE,fp)) {
...
I'm trying to read information printed by program A from program B. How can I pass data from A to B using read()?.
code for A
#include <stdio.h>
int main(int argc, char **argv)
{
int i, j;
char instruc_list[11][3] = {"sa", "sb", "ss", "pa", "pb",
"ra", "rb", "rr", "rra", "rrb", "rrr"};
i = 0;
while (i < 11)
{
j = 0;
while (j < 3)
{
printf("%c", instruc_list[i][j]);
j++;
}
i++;
printf("\n");
}
return (0);
}
code for B
int main()
{
char buf[4];
while ((read(0,buf, 4)))
{
printf("%s", buf);
}
printf("\n");
return 0;
}
When I run this two programs, I get the following result.
Use the popen() and pclose() functions defined in stdio.h to pipe output between programs.
Here's an example program of how to print the output of the ls shell command in your program, taken from this link:
FILE *fp;
int status;
char path[PATH_MAX];
fp = popen("ls *", "r");
if (fp == NULL)
/* Handle error */;
while (fgets(path, PATH_MAX, fp) != NULL)
printf("%s", path);
status = pclose(fp);
if (status == -1) {
/* Error reported by pclose() */
...
} else {
/* Use macros described under wait() to inspect `status' in order
to determine success/failure of command executed by popen() */
...
}
For your case, you'd call popen("./A", "r");.
You can use popen() to read the output of program A from program B.
Compile the first program:
gcc a.c -o a
In the program B:
#include <stdio.h>
int main(void)
{
char buf[4];
FILE *fp;
fp = popen("./a", "r");
while( !feof(fp)) {
fscanf(fp, "%s", buf);
printf("%s\n", buf);
}
return 0;
pclose(fp);
}
Now compile and execute the program B:
gcc b.c -o b
me#linux:$ ./b
The output I got is:
sa
sb
ss
pa
pb
ra
rb
rr
rra
rrb
rrr
rrr
In program A, you're not writing the null terminators for the 3-letter strings... and in program B, you're not adding a null char after the characters you read (and haven't initialised buf, so it might not contain one). That's why you're getting garbage between the 3-letter strings you read... printf() is continuing past the characters you read because it hasn't found a null yet.
Also note that read() can return -1 for error, which would still test as true for your while loop. You should at least check that read() returns greater than 0 (rather than just non-zero), if not put in more thorough error handling.
So with some changes to address these issues, program B might become:
int main()
{
char buf[4];
int ret; // ** for the return from read()
while ((ret = read(0,buf, 4)) > 0) // ** read >0 (no error, and bytes read)
{
fwrite(buf, 1, ret, stdout); // ** write the number of chars
// you read to stdout
}
printf("\n");
return 0;
}
As for program A, right now it writes 3 characters for both the 2-letter and the 3-letter strings -- which means it includes the null char for the 2-letter strings but not for the 3-letter strings. With the changes to program B above, you don't need to write the null characters at all... so you could change:
while (j < 3)
to:
while (j < 3 && instruc_list[i][j] != 0)
to stop when the null character is reached (though it's still inefficient to use a printf() call just to write a single char -- perhaps putchar(instruc_list[i][j]); would be better). Or, you could just replace that inner while loop with:
fputs(instruc_list[i], stdout);
...which would then write the string in instruc_list[i] up to but not including the null char, and also change instruc_list[11][3] to instruc_list[11][4] so that it has room for the null char from the 3-letter string literals in the initialiser list.
The implementation of the cat program is printing in binary format on the Ubuntu terminal. I am using the stdout macro (object of type FILE*).
#include <stdio.h>
main(int argc, char** argv)
{
FILE *fp;
void add(FILE*, FILE*);
if (argc==1)
add(stdin,stdout);
else
while(--argc>0)
{
if ((fp=fopen(*++argv,"r"))==NULL)
{
printf("cat:can't open %s\n",*argv);
return 1;
}
else
{
add(fp,stdout); // printing all the file content on the screen.
fclose(fp);
}
return(0);
}
}
void add(FILE*p,FILE*q)
{
int c;
while((c=fgetc(p))!=EOF)
{
fputc(c,q);
}
}
Now, how can I print in text format instead of binary format?
The error is in how you loop over the arguments. Stripping your code of the actual file processing and replacing it with a print statement (and also nicely indenting it), we get:
if (argc == 1)
printf("stdin\n");
else
while (--argv > 0) {
printf("'%s'\n", *++argv);
}
You have mistyped argc for argv in your code. That means you decrement the pointer to the first argument and then increment it again before processing the file. Effectively, you end up processing argv[0] over and over. That file is the program itself, which is binary and contains many non-printable characters.
You should chzange the loop to
while (--argc > 0) {
printf("'%s'\n", *++argv);
}
or use a pedestrian for loop:
for (int i = 1; i < argc; i++) {
printf("'%s'\n", argv[i]);
}
program has no any error only typo mistake argv instead argc rest all is good even than above suggested answer
I'm very new to C, I am attempting to read the contents of one file character by character and output them to the stream. But even with my fopen() command commented out I receive segfault (core dumped).
I must run a command: ./a.out < testWords.in > myOut.txt to execute my file properly.
Here is what I have so far:
#include <stdio.h>
void main(char *fileName[])
{
printf("filename is %s.\n",fileName[0]);
//Get file based on a string inputed
FILE *fp=fopen(fileName[0],"r"); //Fetches our file as read only
char ch;
int lineCount = 0;
int wordCount = 0;
int charCount = 0;
//Failed to find/open file. NULL character.
if (fp == 0) printf("Woops! Couldn't open file!\n");
//While not at end of file, grab next char.
else while( (ch=fgetc(fp)) != EOF)
{
if (ch == '\n') //on newline
{
//Prints (charCount,wordCount)\n lineCount:
printf("(%d,%d)%c%d:",charCount,wordCount,ch,lineCount);
charCount = 0;
lineCount += 1;
}
else printf("%c",ch); //mirrors char.
}
fclose(fp); //Closes file (gotta be tidy!)
}
You can't just invent a way to call main. You need to use one of the standard ways, like this:
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Missing filename\n");
return -1;
}
FILE *fp = fopen(argv[1], "r");
// ...
}
And note that argv[0] contains the program name (if available; if not it contains an empty string).
Your program segfaulted because you received the int argc argument into your char *filename[] parameter. If you ran the program with a single command line parameter, the value passed in as the first argument would have been 2, which is not a valid pointer value. The expression filename[0] dereferences that address and causes a segfault.
Any time you get a segfault in C, you should smell a bad pointer or address in an argument list. In this particular case., the signature of main is always int main(int argc, char** argv). Yours isn't.
What you want is
int main(int argc, char ** argv) {
...
FILE * fp = fopen(argv[1]); // Quiz: why argv[1]? What's argv[0]?
You're getting away with it in the compiler because, basically, luck.
I also notice in your example call, there's actually no argument in the argument list, because you're using redirection.
Use:
int main(int argc, char* argv[])
And use argv[1] as fileName.
Main function must receive always that two parameters.
My program is supposed to read unix command from file, execute it, save result to file. If I simply try to run it from console, there is no problem with execution. If I redirect input to file, however, it for some reason continues to read forever. I think I might not be detecting EOF properly, but this approach seemed to work before.
I tried debugging and results are really strange. or example for a file with input
echo blablabla
true
false
it's input lines will be, in order
echo blablabla
true
falseecho blablabla
As if it read the stdout? Or stdin? But it works if I simply provide input from console.
FILE* script;
script=freopen(argv[argc-1], "r", stdin);
if(script==0){
printf( "Error 1\n" );
return 1;
}
int c;
while((c=fgetc(stdin))){
if(c==EOF || c==4 || c<0){
c='\n';
exitLoop=true;
}
if(c!='\n'){
inLine[i]=c;
inLine[i+1]=0; //shouldn't be needed, but just in case
i++;
}else{
inLine[i]=0;
printf("inLine: %s i:%d\n\n",inLine,i);
sleep(1);
int result= 0;
result= fork();
if(result<0){
printf("Failed creation of a new process. Most likely not enough memory\n");
return 1;
}else if(result==0){
short int ak=childFunction(inLine,logPath,searchPath);
return ak;
}else if(result>0){
int status=0;
int d=(int)waitpid(result,&status,0);
}else
return -1;
}
i=0;
if(exitLoop==true)
break;
}
}
edit:
int childFunction(char in[],char logPath[], char searchPath[]){
FILE *logFile= fopen( logPath, "a" );
if(logFile==NULL)
return 1;
char** argv;
int stringCount=1;
char* path;
int i=0,j=0;
for(i=0;in[i]!=0;i++){
if(in[i]==' ' || in[i]=='\t'){
in[i]=0;
stringCount++;
}
}
argv = malloc(sizeof(char*)*(stringCount+1));
i=0;
argv[0]=in;
j++;
while(j<stringCount){
if(in[i]==0){
argv[j]=in+i+1;
j++;
}
i++;
}
argv[stringCount]=NULL;
int processId=fork();
if(processId<0){
printf("Error while forking.\n");
exit(1);
}else if(processId==0){
return execv(in,argv);
}
int c=0;
waitpid(processId,&c,0);
c=errno;
fprintf(logFile,"%d: %s\n", c, in);
fclose(logFile);
free(argv);
if(c!=0)
return(1);
else
return(0);
}
Your issue is that fgetc() returns an int, not char. Since you want to be able to read any char (i.e. any byte) fgetc() will return the unsigned char value that was entered. EOF is defined as being less than 0, so that it can be distinguished.
You need to define c as an int so that you can identify the EOF, otherwise it will overlap with some valid character's value and as you discovered may not be detectable at all (if char is unsigned).
Okay. No idea what caused the problem. I did manage to go around it however, by reading the length of file beforehand, and simply exiting the loop after x characters were read.