0

As part of a question where I have to pipe processes together, I have to have one process simply send the sequence of integers 1, 2 .....10000 out of standard output. The problem I have is that I can not get it to work decently in any way shape or form.

I have been writing a (very) simple program to try out different methods. When I write to the stdout directly, I get a formless list of 10000 numbers. When I try to write the string of numbers to a file, the text editor freezes when I attempt to open it. The program is as follows:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char* argv[]) {

    char *arg[]= {"/home/eric/Documents/pr3/test.txt"};
    int i;
    int fp = open(arg[0], O_WRONLY);
    char tmp[12]={0x0};
    for(i=1; i<=10000; i++){
        sprintf(tmp,"%11d", i);
        write(fp, &tmp, sizeof(tmp));
    }
} 

I have no idea why that happens and would very much appreciate some help.

Thank you.

Eric31
  • 111
  • 8
  • Fair point. Edited to be legible. – Eric31 Dec 18 '17 at 18:17
  • start by checking the `fd`. – Sourav Ghosh Dec 18 '17 at 18:18
  • 1. `write(fp, &tmp, sizeof(tmp));` -> `write(fp, tmp, sizeof(tmp));`, `tmp` is already a memory address. 2. `tmp` holds a string whose length is `strlen(tmp)` which depends on the string, but you write always `sizeof(tmp)` = 12 bytes, regardless of what `tmp` holds. 3. Check if `open` succeeds. – Jabberwocky Dec 18 '17 at 18:18
  • `write(fp, &tmp, sizeof(tmp));` -> `write(fp, tmp, strlen(tmp));` – Support Ukraine Dec 18 '17 at 18:25
  • Hello, thanks for your reply. I have made the 3 changes suggested, but the editor continues to freeze. Could it be anything else? – Eric31 Dec 18 '17 at 18:26
  • Please use a hex dump utility to find out what is actually getting put in the file, and post the first few lines of the output. It would also be helpful if you told us exactly which text editor you are using. – zwol Dec 18 '17 at 18:31
  • Incidentally, that `open` call probably ought to be `open("...", O_WRONLY|O_CREAT|O_TRUNC, 0666)`. – zwol Dec 18 '17 at 18:32
  • Indeed it seems to work. I will investigate the flags in the man page, can you tell me what the 0666 means? Thank you all – Eric31 Dec 18 '17 at 18:35
  • it's a bit mask for the permissions of the file created. Each octal number represents permissions for user, group and others. In this case: read (4) + write (2) for everyone. You will easily find a complete description by googling – Ingo Leonhardt Dec 18 '17 at 18:49
  • You're not putting any newlines between the numbers, so you're creating a single line that's over 40K characters wide. Your editor may have trouble with such a long line. – Barmar Dec 18 '17 at 19:06
  • As a general rule, use `int fd;` for file descriptors from `open()` and many other system calls, and `FILE *fp;` for file streams from `fopen()` and a few of its friends. If people see `fp` applied to `write()`, they wonder what's going on; similarly, `fprintf(fd, …)` would ring alarm bells. It isn't precisely 'wrong' to use `fp` for a file descriptor; it is aconventional, though. – Jonathan Leffler Dec 18 '17 at 19:09
  • 1
    The 0666 means that you don't care about the security of the data you write, and the onus is on the user of your program to set [`umask()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/umask.html) (via the [`umask`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/umask.html) command) appropriately to protect themselves from programs that use permissions like 0666 in the calls to `open()`. IMO, you should be using 0644 usually, so only the owner of the file can modify it. If the owner wants to let others share editing responsibilities, they can change the permissions. – Jonathan Leffler Dec 18 '17 at 19:12
  • 3
    That said, `0666` has history on its side; that is the classic value used on Unix systems, though IMO that legacy dates back to a more innocent time when there wasn't an internet and there weren't people trying to break things. – Jonathan Leffler Dec 18 '17 at 19:14
  • If the file exists, your program will overwrite it with 10,000 blocks of 12 bytes, which will contain an ASCII number with multiple null bytes padding the value. If that's not what you wanted, you have work more carefully. You might only print `strlen(tmp)` bytes, you should specify `tmp` and not `&tmp` in the call to write (there's a big difference between a `char *` and a `char (*)[]`, though you'd be hard put to spot it because of the way things work), and you would need to think what character you want separating the numbers (none, a null byte, a newline, something else). – Jonathan Leffler Dec 18 '17 at 19:18
  • The standard output is called `stdout`. It is a `FILE*`. You can `printf` or `fprintf` fo it. There is no need to `open` or `write` anything. – n. m. could be an AI Dec 18 '17 at 19:39
  • 1
    Maybe your text editor is bad at handling very long text lines. You write 10000 numbers on a single line. Try writing the numbers on separate lines, `sprintf(tmp,"%11d\n", i);` – nos Dec 18 '17 at 19:44

1 Answers1

2

You may have a permissions issue. By default open() creates a file with permissions that would cause you some issues when viewing the file. Look at the changes I made to the open() call. You will need to delete the file each time.

Also using sizeof() is incorrect. You should use the length of the string that you wrote using sprintf(). I prefer to take the output from sprintf(), but I believe strlen() will give you the same number. After changing this I was able to open the file in a text editor.

I also added an error check to ensure your file is open.

Also close your file.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char* argv[]) {

    char *arg[]= {"/home/eric/Documents/pr3/test.txt"};
    int i;
    int fp = open(arg[0], O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
    if(fp<0){
    // do some error msg here
    }

    char tmp[12]={0x0};
    int size = 0;
    for(i=1; i<=10000; i++){
        size = sprintf(tmp,"%11d", i);
        write(fp, &tmp, size);
    }
    close(fp);
    return 0;
}
Maniac
  • 36
  • 4
  • You can also use `fdopen` to get a more regular `FILE *` and use `fprintf` directly, or (unless there is a reason not to?) immediately use `fopen`. – Jongware Dec 18 '17 at 23:37
  • 1
    There are few differences that may be at play. This [answer](https://stackoverflow.com/questions/1658476/c-fopen-vs-open) from a few years ago is a nice explanation. – Maniac Dec 19 '17 at 16:10