C open() returns -1 for a path string - c

when i use open() as
int ff=open("/home/user/desktop/bla/test",O_RDONLY);
it works fine.
but when i use a string as the (same path stored in a string) path it doesn't work.
int ff=open(string,O_RDONLY);
why is this?
this is my whole code. i'm confused. i know it should work. but i doesn't. i can't find the bug.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
void bla(char *);
int main(void)
{
// int i;
FILE * fp=fopen("path","r");
char line[256];
while( fgets(line,255,fp)!=NULL){
bla(line);
}
return 0;
}
void bla(char * line){
int status;
printf("%s",line);
pid_t pid=fork();
char string[256];
if(pid==0){
pid=wait(&status);
int ff=open(line,O_RDONLY);
if(ff<0){
printf("\topen error!\n\n");
return;}
int ret=read(ff,string,255);
if(ret<0){
printf("read error!\n");
return;}
printf("%s",string);
close(ff);
exit(0);
}
if (pid>0){
return;
}
}
in bla function, if i replace 'line' with the path, it works. i used a printf to make sure. path is the same (it seems the same).

I call shenanigans :-)
Obviously, if string were exactly the same value as your string literal, and all others things remained the same, it would work fine.
So, if all other things are the same, string is obviously not set to the value you think it is, to wit "/home/user/desktop/bla/test".
My advice would be to print it out (along with an error string) to be sure, something like:
fprintf (stderr, "DEBUG: string is [%s]\n", string);
int ff = open (string, O_RDONLY);
if (ff < 0)
perror ("Could not open file");
And, now that you've posted the code, your problem is obvious: fgets() does not remove the trailing newline so, were you to add the code I proposed above, you would see:
DEBUG: string is [/home/user/desktop/bla/test
]
and deduce the problem.
A quick way to fix this is to remove the newline yourself, with something like:
while (fgets (line, 255, fp) != NULL) {
size_t ln = strlen (line); // Add these
if ((ln > 0) && (line[ln-1] == '\n')) // three
line[ln-1] = '\0'; // lines.
bla (line);
}

Related

Loop through text file after filtering out comments in C

I am trying to filter out comments from a text file denoted by '#'. I am having trouble looping through the entire file and printing the output to the terminal. The code removes the first line of text and the second lines comments as it should but does not continue past line 2 (prints 4, 2), any help would be appreciated. I'm definitely missing something as I have had to learn two semesters of C in a weekend and don't totally have a grasp on all of its usage.
The file being read
# this line is a full comment that might be pseudo-code or whatever
4, 2 # 4, 3
1
# 9
7
endNode
endNet
The program
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 1024
#define COMMENT_MARKER '#'
int main()
{
FILE *fp;
char buffer[BUFF_SIZE];
if ((fp = fopen("F:\\PythonProjects\\C\\text.txt", "r")) == NULL)
{
perror("Error opening file");
exit(1);
}
while (fgets(buffer, BUFF_SIZE, fp) != NULL)
{
char *comment = strchr(buffer, COMMENT_MARKER);
if (comment != NULL)
{
size_t len = strlen(comment);
memset(comment, '\0', len);
printf("%s", buffer);
}
}
fclose(fp);
}
Your current code only prints out a line if a # is found in it. It skips printing lines without any comment. And because you set everything from the first # to the end of the string to nul bytes, it won't print a newline after each line, meaning the results all run together.
You can fix these issues by moving the output after the comment removal block, and always printing out a newline. This means that in lines without comments, you have to do something about the newline at the end (if any; it could be missing because of a long line or the input file lacking one after the last line) so you don't get two newlines after each non-comment line.
Luckily, there are ways in standard C to find the first occurrence of one of a set of character, not just a single character. You can look for either the comment character or newline in a single pass through the line, and replace it with a single nul byte - no need to memset() everything after it to 0's. Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // Needed for exit()
#define BUFF_SIZE 1024
#define COMMENT_MARKER '#'
int main()
{
FILE *fp;
char buffer[BUFF_SIZE];
if ((fp = fopen("text.txt", "r")) == NULL)
{
perror("Error opening file");
exit(1);
}
char tokens[3] = { COMMENT_MARKER, '\n', '\0' };
while (fgets(buffer, BUFF_SIZE, fp) != NULL)
{
// Look for the first # or newline in the string
char *comment_or_nl = strpbrk(buffer, tokens);
if (comment_or_nl)
{
// and if found, replace it with a nul byte
*comment_or_nl = '\0';
}
// Then print out the possibly-truncated string (puts() adds a newline)
puts(buffer);
}
fclose(fp);
return 0;
}
Here is your code, minimally adapted to achieve the objective.
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 1024
#define COMMENT_MARKER '#'
int main()
{
FILE *fp;
if ((fp = fopen("F:\\PythonProjects\\C\\text.txt", "r")) == NULL)
{
perror("Error opening file");
exit(1);
}
char buffer[BUFF_SIZE]; // declare variables proximate to use
while (fgets(buffer, BUFF_SIZE, fp) != NULL)
{
char *comment = strchr(buffer, COMMENT_MARKER);
if (comment != NULL)
{
strcpy( comment, "\n" ); // Just clobber the comment section
}
printf("%s", buffer); // Always print something
}
fclose(fp);
}

How to write text containing newline given as command line arguments in C?

I want to create a text file with mulitple lines using system calls in C and populate it with the text provided as command line arguments.
This is what I wrote:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_SZ 1024
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Invalid Number of arguments\n");
printf("USAGE: ./a.out file_name \"msg\"\n");
} else {
int fd_creat, fd_open, fd_write;
char file_name[MAX_SZ];
char *msg = (char *)malloc(strlen(argv[2]) * sizeof(char));
strcpy(file_name, argv[1]);
fd_creat = creat(file_name, 0777);
if (fd_creat < 2) {
printf("ERROR: File could not be created\n");
} else {
fd_open = open(file_name, O_WRONLY);
strcpy(msg, argv[2]);
fd_write = write(fd_open, msg, strlen(msg));
close(fd_open);
}
}
return 0;
}
If I execute this program as:
./a.out test.txt "Foo\nBar"
It writes the whole thing into test.txt as it is. Basically, I want 'Foo' and 'Bar' in their separate lines.
There's two problems here:
The way you're handling arguments and failing to allocate enough memory for the data involved,
Interpreting escape sequences like \n correctly since the shell will give them to you as-is, raw.
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
// This moves overlapping strings from src -> dest but only
// if dest is before src
void cc_str_drag(char* dest, char* src) {
while (*dest) {
*dest = *src;
++dest;
++src;
}
}
// This interprets the \n sequence and can be extended to handle others, like
// \t, \\, or even \g.
void cc_interpret(char* str) {
for (;*str; ++str) {
// If this is a sequence start...
if (*str == '\\') {
// ...find out which one...
switch (str[1]) {
case 'n':
// Shift back...
cc_str_drag(str, &str[1]);
// ...and replace it.
*str = '\n';
break;
}
}
}
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Invalid Number of arguments\n");
// Remember argv[0] is the name of the program
printf("USAGE: %s file_name \"msg\"\n", argv[0]);
return -1;
}
// Since it's not the 1970s, use fopen() and FILE*
FILE* output = fopen(argv[1], "w");
if (!output) {
printf("ERROR: File could not be created\n");
return -2;
}
// Copying here to avoid tampering with argv
char* str = strdup(argv[2]);
// Replace any escape sequences
cc_interpret(str);
// Then just dump it directly into the file
fwrite(str, 1, strlen(str), output);
fclose(output);
return 0;
}
Note the tools used here:
strdup is a way quicker method of copying a C string than malloc(strlen(s)) and then copying it. That's asking for dreaded off-by-one errors.
FILE* performs much better because it's buffered. open() is used for low-level operations that can't be buffered. Know when to use which tool.
Don't be afraid to write functions that manipulate string contents. C strings are really important to understand, not fear.

C language File io

I am trying to read a file in C language
#include <stdio.h>
#include <unistd.h>
int main(void){
char *pathname = "Dictionary_korean.txt";
if(access(pathname, R_OK) == 0)
puts("It's OK to read");
else
puts("no authority");
}
I wrote ths code to see that if this .txt file is not able to read.
but the result of this code was 'It's OK to read'.
so I wrote a another code
#include <stdio.h>
#include <unistd.h>
int main(void){
char str[100];
char ch;
FILE * src = fopen("Dictionary_korean.txt", "rt");
if(src == NULL || des == NULL){
puts("Failed to open the FILE");
return -1;
}
fgets(str, sizeof(str), src);
printf("%s", str);
fgets(str, sizeof(str), src);
printf("%s", str);
fclose(src);
return 0;
}
this is the second code. In this code, the result has to be the 2 strings in the 'Dictionary_korean.txt' File, but it only prints '?'
so I thought that my program had had an error.
so, I copied the 'Dictionary_korean.txt' file to 'BBB.txt' File and made a same code depending on the 'BBB.txt', and it worked properly.
I also checked the authority of the 'Dictionary_korean.txt' Note pad file, but it had all of the authority it can have.
what do you think the problem is?

Data entry into array of character pointers in C

this is my first question asked on here so if I'm not following the formatting rules here please forgive me. I am writing a program in C which requires me to read a few lines from a file. I am attempting to put each line into a cstring. I have declared a 2D character array called buf which is to hold each of the 5 lines from the file. The relevant code is shown below
#include <stdlib.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h> /* UNIX domain header */
void FillBuffersForSender();
char buf[5][2000]; //Buffer for 5 frames of output
int main()
{
FillBuffersForSender();
return 0;
}
void FillBuffersForSender(){
FILE *fp;
int line = 0;
char* temp = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("frames.txt", "r");
printf("At the beginning of Fill Buffers loop.\n");
//while ((read = getline(&temp, &len, fp)) != -1){
while(line < 5){
//fprintf(stderr, "Read in: %s\n", temp);
fgets(temp, 2000, fp);
strcpy(buf[line], temp);
line++;
fprintf(stderr, "Line contains: %s.\n", temp);
temp = NULL;
}
while(line != 0){
fprintf(stderr, "Line contains: %s.\n", buf[line]);
line--;
}
}
The line
strcpy(buf[line], temp);
is causing a segmentation fault. I have tried this numerous ways, and cannot seem to get it to work. I am not used to C, but have been tasked with writing a bidirectional sliding window protocol in it. I keep having problems with super basic issues like this! If this were in C++, I'd be done already. Any help anyone could provide would be incredible. Thank you.
temp needs to point to an allocated buffer that fgets can write into.
In C programming, error checking is an important part of every program (in fact sometimes it seems like there's more error handling code than functional code). The code should check the return value from every function to make sure that it worked, e.g. if fopen returns NULL then it wasn't able to open the file, likewise if fgets returns NULL it wasn't able to read a line.
Also, the code needs to clean up after itself. For example, there is no destructor that closes a file when the file pointer goes out of scope, so the code needs to call fclose explicitly to close the file when it's finished with the file.
Finally, note that many of the C library functions have quirks that need to be understood, and properly handled. You can learn about these quirks by reading the man pages for the functions. For example, the fgets function will leave the newline character \n at the end of each line that it reads. But the last line of a file may not have a newline character. So when using fgets, it's good practice to strip the newline.
With all that in mind, the code should look like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 5
#define MAXLENGTH 2000
static char buffer[MAXLINE][MAXLENGTH];
void FillBufferForSender(void)
{
char *filename = "frames.txt";
FILE *fp;
if ((fp = fopen(filename, "r")) == NULL)
{
printf("file '%s' does not exist\n", filename);
exit(1);
}
for (int i = 0; i < MAXLINE; i++)
{
// read a line
if (fgets( buffer[i], MAXLENGTH, fp ) == NULL)
{
printf("file does not have %d lines\n", MAXLINE);
exit(1);
}
// strip the newline, if any
size_t newline = strcspn(buffer[i], "\n");
buffer[i][newline] = '\0';
}
fclose(fp);
}
int main(void)
{
FillBufferForSender();
for (int i = 0; i < MAXLINE; i++)
printf("%s\n", buffer[i]);
}
Note: for an explanation of how strcspn is used to strip the newline, see this answer.
When it comes to C you have to think of the memory. Where is the memory for a point with NULL assigned to it? How can we copy something to somewhere that we have no space for?

Difficulty using malloc and scanf

I have difficulty using malloc and fscanf.
I just want to read a file and print out the result using
I got a segmentation fault error when I executed this code.
I am not sure what I have done wrong. I would be very grateful if someone points out a fix.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
char* buffer = (char*)malloc(*argv[1]); // Allocate memory
if(buffer=NULL) // if *argv[1] is not existed, exit the program
exit(1);
int n = 0;
FILE* fp=fopen("file.txt","r"); // Open the file
do {
buffer[n] =fscanf(fp,"%c",buffer); // read from file until it gets EOF
} while(buffer[n] != EOF);
fclose(fp); // Close the file
printf("%s",buffer); // Print the stored string
free(buffer); // Return the memory
return 0;
}
Got it. This:
if(buffer=NULL)
should be this:
if(buffer==NULL)
You're setting buffer to NULL. I'm sure you can see what happens next.
More generally, this code is trying to do several things, and it's full of bugs. You should have tested the different functions separately and worked out those bugs along the way.
This here seems wrong:
char* buffer = (char*)malloc(*argv[1]);
The command line argument is a string, but you want a number. You have to convert the string to a number first.
Another problem: In your loop n is never increased, which is why only the first byte of the buffer is written.
Please find the fixed code and the comments inline:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
// Add the check if *argv[1] does not exist, exit the program
long mem_sz=strtol(argv[1],NULL,10);//Safer to atoi
char* buffer = (char*)malloc(mem_sz); // properly allocate memory
//You missed the == in the NULL check.
if(buffer==NULL)
exit(1);
int n = 0;
FILE* fp=fopen("file.txt","r"); // Open the file
if (fp == NULL)//Check fp too
exit(1);
do
{
buffer[n++]=fscanf(fp,"%c",buffer);
} // read from file until it gets EOF and n++
while(buffer[n-1] != EOF);//Check the last read character
buffer[n]=0;//Put an end of string, so that printf later will work correct
fclose(fp); // Close the file
printf("%s\n",buffer); // Print the stored string
free(buffer); // Return the memory
return 0;
}

Resources