I'm trying to remove a file in a folder using C but it's crashing & throwing me some return value
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
FILE *fp1;
char str[100];
gets(str);
strcat(str,"txt");
fp1 = fopen(str,"r");
fclose(fp1);
remove(str);
return 0;
}
This is not working. I'm using windows XP SP2 (32 bit) and also tried system() command in the C program, but No help. Can anyone please help to fix this issue?
It is unclear why you are calling fopen, you are not reading anything from it. If you are attempting to use it as a check for the file's existence, there is no need, the return from remove will tell you whether the removal was successful.
For example, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#define EXT ".txt"
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
int main (void) {
char buf[PATH_MAX] = "";
size_t len = 0;
printf ("enter filename to delete (without .txt); ");
if (!fgets (buf, sizeof buf, stdin) || *buf == '\n') {
fprintf (stderr, "error: EOF or invalid input.\n");
return 1;
}
len = strlen (buf); /* get length */
if (buf[len - 1] == '\n') /* check trailing '\n' */
buf[--len] = 0; /* overwrite with '\0' */
else {
/* handle error, input exceeded buf size */
return 1;
}
strcat (buf, EXT);
errno = 0;
if (remove (buf) == -1)
perror ("remove failed");
else
printf ("file: '%s' successfully removed.\n", buf);
return 0;
}
Example Use/Output
$ ls -al foobar.txt
-rw-r--r-- 1 david david 0 Sep 17 06:35 foobar.txt
$ ./bin/rmfile
enter filename to delete (without .txt); foobar
file: 'foobar.txt' successfully removed.
$ ./bin/rmfile
enter filename to delete (without .txt); foobar
remove failed: No such file or directory
It works the same on Linux or DOS (you just need to define PATH_MAX on windows).
Example Use/Output on Windows
c:\Users\david\Documents\dev\src-c\tmp>cl /Wall /Ox /Febin\rmfile rmfile.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
rmfile.c
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:bin\rmfile.exe
rmfile.obj
c:\Users\david\Documents\dev\src-c\tmp>echo "test on Windoze" > foobar.txt
c:\Users\david\Documents\dev\src-c\tmp>dir foobar.txt
Volume in drive C has no label.
Volume Serial Number is 2045-D579
Directory of c:\Users\david\Documents\dev\src-c\tmp
09/17/2017 06:56 AM 20 foobar.txt
1 File(s) 20 bytes
0 Dir(s) 20,235,399,168 bytes free
c:\Users\david\Documents\dev\src-c\tmp>bin\rmfile
enter filename to delete (without .txt); foobar
file: 'foobar.txt' successfully removed.
c:\Users\david\Documents\dev\src-c\tmp>bin\rmfile
enter filename to delete (without .txt); foobar
remove failed: No such file or directory
I guess if you are on windows, you should probably define the following at the top of the file to remove the strcat warning from the compiler:
#if defined (_WIN32) || defined (_WIN64)
#define _CRT_SECURE_NO_WARNINGS
#endif
Related
I am learning c++ and the excersise involves opening a .txt file and reading from it.
The project structure is as following:
int main()
{
static const char* full_name = "C:\Users\Lukas\Desktop\Programming\file_system_test\file_system_test\items.txt";
FILE* my_file = fopen(full_name , "r");
if (my_file == NULL) {
perror("error opening file");
}
}
I am trying to fopen items.txt but with no luck yet..
I am not exactly sure what is the problem since I provide the full path..
METHODS TRIED SO FAR:
Using double backslash in full path
static const char* full_name = "C:\\Users\\Lukas\Desktop\\Programming\\file_system_test\\file_system_test\\items.txt";
Error still persists with:
error opening file: No such file or directory
SOLVED
The only thing that seems to fix this code is to use raw string literal as following:
static const char* full_name3 = R"(C:/Users/Lukas/Desktop/Programming/file_system_test/file_system_test/items.txt)";
FILE* my_file3 = fopen(full_name3, "r");
if (my_file3 == NULL) {
perror("error opening file");
}
Does not return any errors anymore.
Note escape sequences of string literals, so your path:
static const char* full_name = "C:\Users\Lukas\Desktop\Programming\file_system_test\file_system_test\items.txt";
contains \f escape sequence which is interpreted as form feed - new page byte 0x0c in ASCII encoding. This character can't be part of of a path so Invalid argument error is reported.
Also compilers complain that other escape sequences are unknown.
There are three ways to fix it.
As Luka Rahne suggested by using back slash escape sequence \\
Or by using forward slashes (since C suppose to be portable, standard library is able to convert Unix path separator to platform specific path separators).
static const char* full_name = "C:/Users/Lukas/Desktop/Programming/file_system_test/file_system_test/items.txt";
If you are using C++11 or newer (your code is C not C++, but tag says C++), you can leverage raw string literal:
static const char* full_name = R"(C:\Users\Lukas\Desktop\Programming\file_system_test\file_system_test\items.txt)";
Here I did some live testing with msvc (file named: open.c):
#include <stdlib.h>
#include <stdio.h>
int main(int argc, const char argv[])
{
#if VERSION == 0
// here '\f' is used to reproduce error "invalid argument":
static const char name[] = "C:\fUsers\\User\\Downloads\\open.c";
#elif VERSION == 1
static const char name[] = "C:\\Users\\User\\Downloads\\open.c";
#elif VERSION == 2
static const char name[] = "C:/Users/User/Downloads/open.c";
#elif VERSION == 3
static const char name[] = R"(C:\Users\User\Downloads\open.c)";
#endif
FILE* f = fopen(name, "r");
if (!f) {
perror("fopen");
return 1;
}
char buf[256] = "";
fgets(buf, sizeof(buf), f);
printf("%s\n", buf);
fclose(f);
return 0;
}
Here is result of compiling and running from cmd.exe:
C:\Users\User\Downloads>cl open.c /D VERSION=0 && open.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29336 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
open.c
Microsoft (R) Incremental Linker Version 14.28.29336.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:open.exe
open.obj
fopen: Invalid argument
C:\Users\User\Downloads>cl open.c /D VERSION=1 && open.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29336 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
open.c
Microsoft (R) Incremental Linker Version 14.28.29336.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:open.exe
open.obj
#include <stdlib.h>
C:\Users\User\Downloads>cl open.c /D VERSION=2 && open.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29336 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
open.c
Microsoft (R) Incremental Linker Version 14.28.29336.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:open.exe
open.obj
#include <stdlib.h>
C:\Users\User\Downloads>cl open.c /D VERSION=3 && open.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29336 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
open.c
open.c(11): warning C4129: 'm': unrecognized character escape sequence
open.c(11): warning C4129: 'D': unrecognized character escape sequence
open.c(11): warning C4129: 'o': unrecognized character escape sequence
open.c(11): error C2065: 'R': undeclared identifier
open.c(11): error C2143: syntax error: missing ';' before 'string'
open.c(11): error C2099: initializer is not a constant
So everything works as I described and last version 3 fails since I compile code as C.
I believe your issue is that \ in filename is not properly escaped.
Your filename string should have double backslash characters.
static const char* full_name = "C:\\Users\\Lukas\\Desktop\\Programming\\file_system_test\\file_system_test\\items.txt";
You can test this, by sending this string trough std::cout for debug.
Almost minimal reproducible example:
prog.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *buffer;
int c;
size_t bufsiz = 1024, i = 0;
if (!(buffer = malloc(bufsiz))) {
fputs("malloc() failed!\n", stderr);
return 1;
}
while (EOF != (c = fgetc(stdin))) {
buffer[i] = c;
if (++i == bufsiz && !(buffer = realloc(buffer, bufsiz *= 2))) {
fputs("realloc() failed! (loop)\n", stderr);
return 1;
}
}
buffer[i] = '\0';
if (!(buffer = realloc(buffer, i))) {
fputs("realloc() failed! ", stderr);
fprintf(stderr, "%d\n", i);
return 1;
}
fputs(buffer, stdout);
return 0;
}
I use this command to compile and run:
gcc prog.c -o prog
This command copies the content of prog.c to exp as expected:
cat prog.c | ./prog > exp
This command prints the error message “realloc() failed! 0”:
cat prog.c | ./prog > prog.c
I have yet to find out the reason behind this peculiar behavior...
P.S.: I am using GNU cat and bash
Congratulations, you've (re-)discovered a bug in your system's implementation of realloc, whereby "success" resizing to 0 is indistinguishable from an error. As specified, if realloc returns a null pointer, it has failed and the old object still exists. But some historical implementations treat realloc(p,0) as free(p). Future versions of the C standard allow for this behavior, and deprecate the use of realloc with a zero size, so if you want to use realloc like this you should make sure you are not passing a zero size.
As noted by Eric Postpischil in a comment:
Where does your program put a null character at the end of the string in the buffer?
the fact that 0 is a possible size for your buffer is indicative of a problem - you forgot to reserve space for terminating the string - and if you fix this, even a zero-length string takes a nonzero number of bytes.
In cat prog.c | ./prog > prog.c, the shell parses the command, sees there is a redirection into prog.c, and opens prog.c for writing, which erases any previous contents of the file. Then cat prog.c sees an empty file and copies it to standard output. ./prog faithfully reproduces this empty stream.
On Ubuntu we can extract full path of exe of running process by reading /proc/'pid'/exe.
On solaris there is no 'exe' file in /proc/'pid'.
I read the psinfo. But it gives just the name of process and arguments. It does not have full path of exe.
On solaris how can we do this?
My solaris version is 11.3.
Through command, you can get the full path of the exe running like this:
# ls -l /proc/<pid>/path/a.out
For e.g.
# ls -l /proc/$$/path/a.out
lrwxrwxrwx 1 root root 0 Nov 24 17:19 /proc/14921/path/a.out -> /usr/bin/bash
This way you can get the executable path.
More convinient way is:
# readlink -f /proc/<pid>/path/a.out
For e.g.:
# readlink -f /proc/$$/path/a.out
/usr/bin/bash
And programmatically you can do it like this:
#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char *argv[]) {
char outbuf[BUF_SIZE] = {'\0'};
char inbuf[BUF_SIZE] = {'\0'};
ssize_t len;
if (argc != 2) {
printf ("Invalid argument\n");
return -1;
}
snprintf (inbuf, BUF_SIZE, "/proc/%s/path/a.out", argv[1]);
if ((len = readlink(inbuf, outbuf, BUF_SIZE-1)) != -1) {
outbuf[len] = '\0';
} else {
perror ("readlink failed: ");
return -1;
}
printf ("%s\n", outbuf);
return 0;
}
It's usage:
# ./a.out <pid>
Unsure for Solaris, but some old unixes, the only thing that could be retrieved was the command name in argv[0]. Then we had to search that command in the PATH environment variable in correct order to find the full path of the command.
A bit manual but bullet proof.
Apologies if this has been answered, but I haven't found an answer that solves my problem.
I'm trying to pass a system string in C: the bash version of the command is
grep -w "dog\|animal" myfile
I have the following C code:
char str[50] ="dog\\|animal";
char file[50]="myfile";
char buf[20];
snprintf(buf, sizeof(buf), "grep -w \"%s\" %s",str,file);
system(buf);
When I compile and run it I am given this error:
sh: 1: Syntax error: Unterminated quoted string
Minimum example:
#include <stdio.h>
#include <string.h>
int main(){
char str[50] ="dog\\|animal";
char file[50]="myfile";
char buf[20];
snprintf(buf, sizeof(buf), "grep -w \"%s\" %s",str,file);
system(buf);
}
Transferring comment into answer.
You have two component strings size 50, and you try to squeeze them into a 20-byte target. You should be using perhaps 200 instead of 20.
At any rate, 20 is too short. You have 12 characters of overhead plus 6 in the file name and 11 in the match pattern. That's not going to lead to happiness. (Note that if you had checked the return from snprintf(), it would tell you it needs more space than you gave it.). And the most elementary debug technique would add printf("[%s]\n", buf) to show you what is being executed.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char str[50] = "dog\\|animal";
char file[50] = "myfile";
char buf[20];
int size;
if ((size = snprintf(buf, sizeof(buf), "grep -w \"%s\" %s", str, file)) >= (int)sizeof(buf))
printf("Oops! (%d) ", size);
printf("[%s]\n", buf);
system(buf);
return 0;
}
Example output (program name sh11):
$ ./sh11
Oops! (28) [grep -w "dog\|anima]
sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file
$
Note that the size returned by sprintf() does not include the null terminator; the buffer needs to be at least 29 bytes to hold everything.
I want to match the regex (?<=SEARCH_THIS=").+(?<!"\n) in C with PCRE.
However, the following code doesn't work as expected.
#include <pcreposix.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
regex_t re;
regmatch_t matches[2];
char *regex = "(?<=SEARCH_THIS=\").+(?<!\"\n)";
char *file = "NO_MATCH=\"0\"\nSOMETHING_ELSE=\"1\"\nSOME_STUFF=\"1\"\nSEARCH_THIS=\"gimme that\"\nNOT_THIS=\"foobar\"\nTHIS_NEITHER=\"test\"\n";
puts("compiling regex");
int compErr = regcomp(&re, regex, REG_NOSUB | REG_EXTENDED);
if(compErr != 0){
char buffer[128];
regerror(compErr, &re, buffer, 100);
printf("regcomp failed: %s\n", buffer);
return 0;
}
puts("executing regex");
int err = regexec(&re, file, 2, matches, 0);
if(err == 0){
puts("no error");
printf("heres the match: [.%*s]",matches[0].rm_eo-matches[0].rm_so,file+matches[0].rm_so);
} else {
puts("some error here!");
char buffer[128];
regerror(err, &re, buffer, 100);
printf("regexec failed: %s\n", buffer);
}
return 0;
}
The console output is:
compiling regex
executing regex
some error here!
regexec failed: No match
I verified the functionality of this regex here
Any idea what is going wrong here?
EDIT #1
Compiler Version
$ arm-merlin-linux-uclibc-gcc --version
arm-merlin-linux-uclibc-gcc (GCC) 4.2.1
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compile Command
$ arm-merlin-linux-uclibc-gcc -lpcre ./re_test.c -o re_test.o
There are actually a few issues with your code.
First, you use %*s in an attempt to restrict the length of the printed string. However, the integer width before the s formatter is the minimum length of what gets printed; if the corresponding string's length is less than what's given, it'll be padded with spaces. If the length is greater than what's given, it'll just output the whole string. You'll need some other method of restricting the length of the outputted string (just avoid modifying *file, because file points to a constant string).
Second, you specify the REG_NOSUB option in your regcomp call, but according to the man page, this means that no substring positions are stored in the pmatch argument - thus, even if your regexec did work, the following printf would be using uninitialized values (which is undefined behavior).
Finally, I suspect the problem is that the \" and \n characters need to be doubly-escaped; i.e. you need to use \\\" and \\n in your regex string. While the code you gave worked for me (Ubuntu 14.04 x64), the doubly-escaped version also works.
Taking all of this into account, this is the output I get:
compiling regex
executing regex
no error
heres the match: [.gimme that"]