I have a task and I need your advice
I run my program with arguments, like
./program.x input.txt output.txt
So in my program I check that I use properly arguments
if (argc != 3) {
printf("Wrong arguments number\n");
printf("I should run this way:\n");
printf("%s source result\n",argv[0]);
exit(1);
}
if( (wz= fopen(argv[1],"r")) == NULL) {
printf("Open error %s\n", argv[1]);
exit(1);
}
if( (wc= fopen(argv[2],"w")) == NULL) {
printf("Open error %s\n", argv[2]);
exit(2);
}
I also use assert to check that file is ok, they told us that we must use assert too
assert((wz = fopen(argv[1] ,"r")));
assert((wc = fopen(argv[2] ,"w")));
But I dont know I should first put assert, or first checking number of arguments?
if (argc != 3) {
printf("Wrong arguments number\n");
printf("I should run this way:\n");
printf("%s source result\n",argv[0]);
exit(1);
}
if( (wz= fopen(argv[1],"r")) == NULL) {
printf("Open error %s\n", argv[1]);
exit(1);
}
if( (wc= fopen(argv[2],"w")) == NULL) {
printf("Open error %s\n", argv[2]);
exit(2);
}
assert((wz = fopen(argv[1] ,"r")));
assert((wc = fopen(argv[2] ,"w")));
or
if (argc != 3) {
printf("Wrong arguments number\n");
printf("I should run this way:\n");
printf("%s source result\n",argv[0]);
exit(1);
}
if( (wz= fopen(argv[1],"r")) == NULL) {
printf("Open error %s\n", argv[1]);
exit(1);
}
if( (wc= fopen(argv[2],"w")) == NULL) {
printf("Open error %s\n", argv[2]);
exit(2);
}
assert((wz = fopen(argv[1] ,"r")));
assert((wc = fopen(argv[2] ,"w")));
if (argc != 3) {
printf("Wrong arguments number\n");
printf("I should run this way:\n");
printf("%s source result\n",argv[0]);
exit(1);
}
if( (wz= fopen(argv[1],"r")) == NULL) {
printf("Open error %s\n", argv[1]);
exit(1);
}
if( (wc= fopen(argv[2],"w")) == NULL) {
printf("Open error %s\n", argv[2]);
exit(2);
}
assert(expression) is a macro defined by #include <assert.h>.
If the NDEBUG macro is defined before the #include <assert.h> line then the macro call assert(expression) expands to the void expression ((void)0). Otherwise, it will write an error message to the standard error stream and call abort().
Because assert(expression) might not generate any code, it should not be called if the expression has any side effects. One example of a side effect is assigning a value to a variable (or other lvalue). Another example of a side effect is opening file. The call assert((wz = fopen(argv[1] ,"r"))); does both of those things. The correct way to use assert in this case, is to do perform the operation before the assert call and only use assert to check the result. For example:
wz = fopen(argv[1], "r");
assert(wz != NULL);
The expression wz != NULL has no side effects (assuming wz has not been declared with the volatile type qualifier), so is safe.
OP is using assert as part of an exercise. It should be noted that assert is typically used only to check things that are not expected to fail, and the message it writes to the standard error stream is meant to help the developer discover bugs in the code. However, calling fopen on a command line argument is something that is quite likely to fail, and should normally be handled in a way that is useful to the user of the program, rather than the developer.
Related
I'm trying to make a program to write a number into two different file(binary elf file) offsets using fwrite and fseek but both seems to report writing and seeking correctly but objdump -s 0x2db0 -n 0x16 testseems to show no change. fwrite and fseek called as:
error = fwrite((void*)&value, sizeof(value), 1, file);
seek_error = fseek(file, offset, SEEK_SET);
whole program is executed like bellow and is supposed to write 0x119e at offset 0x2db0 and 0x01:
./patch test 0x01 0x2db0 0x119e
so instead of seeing 119e at both offsets when running objdump no change seems to happen at all.
whole Source code is:(mostly checking for functions return values)
#include <stdio.h>
#include <stdlib.h>
#include <zconf.h>
#include <errno.h>
int main(int argc, char *argv[]){
long error, seek_error;
long value, offset;
if (argc < 5){
fprintf(stderr, "Incorrect arg number\n");
exit(1);
}
FILE* file = fopen(argv[1], "ab");
if (file == NULL){
fprintf(stderr, "Error openning File\n");
perror("fopen() :");
exit(1);
}
printf("\t\t File opened successfully\n");
value = strtol(argv[4], NULL, 16); /* convert target value to int */
if (value == LONG_MIN || value == LONG_MAX){
fprintf(stderr, "Error calling strtol\n");
perror("strtol() :");
exit(1);
}
offset = strtol(argv[2], NULL, 16);
printf("offset is %ld\n", offset);
if (offset == LONG_MIN || offset == LONG_MAX) {
fprintf(stderr, "Error calling strtol during offset\n");
perror("strtol() :");
exit(1);
}
seek_error = fseek(file, offset, SEEK_SET); /* From start go to end*/
if (seek_error != 0){
fprintf(stderr, "Error calling fseek\n");
perror("fseek(): ");
exit(1);
}
printf("File position is: 0x%lx\n", ftell(file));
error = fwrite((void*)&value, sizeof(value), 1, file);
if (error != 1){
fprintf(stderr, "Error calling write\n");
perror("write() :");
exit(1);
}
printf("Number of bytes written %ld\n", error);
offset = strtol(argv[3], NULL, 16);
printf("offset is %ld\n", offset);
if (offset == LONG_MIN || offset == LONG_MAX) {
fprintf(stderr, "Error calling strtol during scond offset\n");
perror("strtol() :");
exit(1);
}
seek_error = fseek(file, offset, SEEK_SET); /* Seek to the new offset */
if (seek_error != 0){
fprintf(stderr, "Error calling second fseek\n");
perror("fseek(): ");
exit(1);
}
printf("File position is: 0x%lx\n", ftell(file));
error = fwrite((void*)&value, sizeof(value), 1, file);
if (error != 1){
fprintf(stderr, "Error calling write\n");
perror("write() :");
exit(1);
}
printf("Number of bytes written %ld\n", error);
fflush(file); /* flush changes not nesessecarly */
error = fclose(file);
if (error != 0){
fprintf(stderr, "error closing file\n");
perror("close() :");
exit(1);
}
}
You're opening the file in append mode with fopen(argv[1], "ab"). So all writes are done at the end of the file, ignoring the position you seeked to.
Use fopen(argv[1], "rb+") instead. r means to open it in read mode, so the file isn't emptied first, and + means that writing is also allowed.
I am trying to define a global pointer variable that can then truly be set in the main function as seen below. However I am getting a segmentation fault anytime I try to use outputName after this. I know it probably has to do with setting the pointer equal to NULL at the beginning... any help on how I could have a global pointer that is then set in main would be very helpful! Here is the part of my code that is giving me errors:
char* outputName = NULL;
int isNumber(char number[]){
int i;
if (number[0] == '-')
i = 1;
while(number[i] != '\0'){
if (!isdigit(number[i]))
return 0;
i++;
}
return 1;
}
void catcher(int signo){
printf("The program is exiting early");
remove(outputName);
exit(1);
}
int main(int argc, char *argv[]){
if (argc != 4){
fprintf(stderr,"Incorrect number of arguments, must supply three.\n");
exit(1);
}
char* inputName = argv[1];
outputName = argv[2];
signal(SIGINT, catcher);
int result = isNumber(argv[3]);
if (result == 0){
fprintf(stderr, "Invalid maximum line length, please enter an integer\n");
exit(1);
}
int maxChars = (atoi(argv[3])) + 1;
if ((maxChars-1) < 1){
fprintf(stderr, "Invalid third maximum line length, please enter an integer greater than zero\
.\n");
exit(1);
}
FILE* inFile = fopen(inputName, "r");
if (inFile == NULL){
fprintf(stderr, "Error while opening %s.\n", inputName);
exit(1);
}
FILE* outFile = fopen(outputName, "w");
if (outFile == NULL){
fprintf(stderr, "Error while opening %s.\n", outputName);
exit(1);
}
char line[maxChars];
int done = 0;
while (!done){
char *readLine = fgets(line, maxChars, inFile);
if (readLine == NULL){
if (errno == 0){
done = 1;
} else {
fprintf(stderr, "Error when reading line from input file");
exit(1);
}
}
int len = strlen(line);
if (line[len-1] != '\n'){
line[len] = '\n';
line[len+1] = '\0';
char current = ' ';
while (current != '\n')
current = getc(inFile);
}
if (!done){
fputs(line, outFile);
if (errno != 0){
fprintf(stderr, "Error when writing line to output file");
exit(1);
}
}
}
return 0;
}
May be signal handler is getting called prior to outputName getting set to non null value, you can try setting signal handler after outputName = argv[2]; in main()
Read carefully signal(7): since your catcher calls printf which is not an async signal safe function, your code has undefined behavior. Also, your printf control string don't end with \n, and since stdout is line-buffered, no output would be done. Prefer sigaction(2) to signal, and install your signal handler after having assigned outputName.
Global variables used in signal handlers should be declared volatile. So declare your char* volatile outputName; at global scope. Then you might have a test like if (outputName != NULL) remove(outputName); in the handler. A common practice is just to set some volatile sig_atomic_t global flag in the signal handler, and test that flag elsewhere.
And your program is likely to not have time to get any signal. You probably should end your main function with some wait (e.g. read from stdin, or usleep(3), or pause(2), or poll(2)....).
Of course, compile your code with all warnings and debug info (gcc -Wall -g) and use the debugger (gdb); I guess that debugger watchpoints should be very useful to find your bug.
The program you are showing is likely to not exhibit any SEGV. So your actual bug is very probably elsewhere.
Perhaps using strace(1) and/or valgrind could also help.
I'm writing code that's supposed to verify that a .txt file is a certain format.
I wrote my code as I saw in a tutorial and in the website
and for some reason my program doesn't even print my file.
Can you tell me what I'm doing wrong?
The code will do something far more complex, but I'm still trying to work on my basics.
Here's my code so far:
int main(int argc, char *argv[]) {
/* argv[0] = name of my running file
* argv[1] = the first file that i receive
*/
define MAXBUFLEN 4096
char source[MAXBUFLEN + 1];
int badReturnValue = 1;
char *error = "Error! trying to open the file ";
if (argc != 2) {
printf("please supply a file \n");
return badReturnValue;
}
char *fileName = argv[1];
FILE *fp = fopen(argv[1], "r"); /* "r" = open for reading */
if (fp != NULL) {
size_t newLen = fread(&source, sizeof(char), MAXBUFLEN, fp);
if (ferror(fp) != 0) {
printf("%s %s", error, fileName);
return badReturnValue;
}
int symbol;
while ((symbol = getc(fp)) != EOF) {
putchar(symbol);
}
printf("finish");
fclose(fp);
}
else {
printf("%s %s", error, fileName);
return badReturnValue;
}
}
I think you need a bit more explanations:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
// there might be a macro BUFLEN defined in stdio
// which size is optimized for reading in chunks.
// Test if avaiable otherwise define it
#ifndef BUFLEN
# define BUFLEN 4096
#endif
int main(int argc, char *argv[])
{
char source[BUFLEN];
char *filename;
FILE *fp;
size_t fpread, written;
char c;
int ret_fclose;
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
// reset errno, just in case
errno = 0;
// work on copy
filename = malloc(strlen(argv[1]) + 1);
if (filename == NULL) {
fprintf(stderr, "Allocating %zu bytes failed\n", strlen(argv[1]) + 1);
exit(EXIT_FAILURE);
}
filename = strcpy(filename, argv[1]);
// try to open the file at 'filename'
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Opening file \"%s\" filename failed\n", filename);
// errno might got set to something usable, check and print
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
// You have two options here. One is to read in chunks of MAXBUFLEN
while ((fpread = fread(&source, 1, BUFLEN, fp)) > 0) {
// Do something with the stuff we read into "source"
// we do nothing with it here, we just write to stdout
written = fwrite(&source, 1, fpread, stdout);
// you can use 'written' for error check when writing to an actual file
// but it is unlikely (but not impossible!) with stdout
// test if we wrote what we read
if ((fpread - written) != 0) {
fprintf(stderr, "We did not write what we read. Diff: %d\n",
(int) (fpread - written));
}
}
// fread() does not distinguish between EOF and error, we have to check by hand
if (feof(fp)) {
// we have read all, exit
puts("\n\n\tfinish\n");
// No, wait, we want to do it again in a different way, so: no exit
// exit(EXIT_SUCCESS);
} else {
// some error may have occured, check
if (ferror(fp)) {
fprintf(stderr, "Something bad happend while reading \"%s\"\n", filename);
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
}
// the other way is to read it byte by byte
// reset the filepointers/errors et al.
rewind(fp);
// rewind() should have reseted errno, but better be safe than sorry
errno = 0;
printf("\n\n\tread and print \"%s\" again\n\n\n\n", filename);
// read one byte and print it until end of file
while ((c = fgetc(fp)) != EOF) {
// just print. Gathering them into "source" is left as an exercise
fputc(c, stdout);
}
// clean up
errno = 0;
ret_fclose = fclose(fp);
// even fclose() might fail
if (ret_fclose == EOF) {
fprintf(stderr, "Something bad happend while closing \"%s\"\n", filename);
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
// The macros EXIT_FAILURE and EXIT_SUCCESS are set to the correct values for
// the OS to tell it if we had an eror or not.
// Using exit() is noot necessary here but there exits teh function atexit()
// that runs a given function (e.g: clean up, safe content etc.) when called
exit(EXIT_SUCCESS);
}
You read from the file twice but only print once.
If the file is to small the first reading will read all of the contents, and the second reading will not produce anything so you don't print anything.
I believe you have to reset the pointer after using fread.
Try fseek(fp, SEEK_SET, 0) to reset the pointer to the beginning of the file. Then print the file.
When I examine argv[1] and argv[2], I can't open and write to them! If I don't write the examine, part all things work. I have to use command line parameters as well.
The main
int main(int argc, char **argv[])
a part of
while (i < MAXADAT && kilep)
{
hianyzofajleredmeny = 1;
if ((argv[2][i] == '.' && argv[2][i + 1] == 'c' && argv[2][i + 2] == 's' && argv[2][i + 3] == 'v' && argv[2][i + 4] == '\0'))
{
hianyzofajleredmeny = 0;
kilep = 0;
}
i++;
What am I doing wrong?
There isn't much magic involved. You don't show enough code for us to know what you're really up to, but this code opens the files specified in argv[1] and argv[2].
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 3)
{
fprintf(stderr, "Usage: %s file1 file2\n", argv[0]);
return 1;
}
char *dot1 = strrchr(argv[1], '.');
if (dot1 == 0 || strcmp(dot1, ".csv") != 0)
{
fprintf(stderr, "%s: file %s is not a CSV file\n", argv[0], argv[1]);
return 1;
}
FILE *fp1 = fopen(argv[1], "r");
if (fp1 == 0)
{
fprintf(stderr, "%s: failed to open %s for reading\n", argv[0], argv[1]);
return 1;
}
char *dot2 = strrchr(argv[2], '.');
if (dot2 == 0 || strcmp(dot2, ".csv") != 0)
{
fprintf(stderr, "%s: file %s is not a CSV file\n", argv[0], argv[2]);
return 1;
}
FILE *fp2 = fopen(argv[2], "w");
if (fp2 == 0)
{
fprintf(stderr, "%s: failed to open %s for writing\n", argv[0], argv[2]);
return 1;
}
char buffer[1024];
size_t nbytes;
while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), fp)) != 0)
fwrite(buffer, sizeof(char), nbytes, fp2);
fclose(fp1);
fclose(fp2);
return 0;
}
It would be sensible to error check fclose(fp2); if it fails, then the output file was not created successfully. It is less crucial to error check fclose(fp1) in general.
The code would benefit from error reporting functions so that the error reporting blocks take up just one line each instead of four, but writing a function to do that job is just a little more complex than you're ready to deal with. Not radically more complex, but enough that I'm not going to overload you with it. The code is very verbose as a result, though.
The code also assumes you have C99 or C11 so you can declare variables at arbitrary points in a function. If you're stuck with C89, then (a) it is time to upgrade to where you can use a standard that's only 15 years old instead of 25 years old, and (b) you'll have to move all the variable declarations to the top of the function and change the initializations into assignments.
I'm writing a program which needs to be able to parse command line arguments, and I would like to use getopt. I have no issues with getting it to work with the regular arguments, however I need it to be able to pick up an argument that is not specified with a flag. For example if I ran: ./prog -a a1 -b b2 foo I would need to be able to get a1,a2 and foo. Right now it handles everything but the unspecified argument. Here is what I have:
while((command = getopt(argc, argv, "a:b:c:")) != -1){
switch(command){
case('a'):
input = fopen(optarg, "r");
if(input == NULL){
printf("Error opening file, exiting\n");
exit( -1 );
}
break;
case('b'):
output = fopen(optarg, "r");
if(output == NULL){
printf("Error opening file, exiting\n");
exit( -1 );
}
break;
case('c'):
keyword = optarg;
break;
case('?'):
if((optopt == 'a') || (optopt == 'b') || (optopt == 'c')){
fprintf(stderr, "Error, no argument specified for -%c\n", optopt);
exit( -1 );
} else
extra = optarg; // This is how I thought I needed to do it
break;
default:
fprintf(stderr,"Error in getopt");
break;
}// switch
} // while
Thanks!
After the loop, the optind variable will be the index to the next non-option argument.
So do e.g.
if (optind < argc)
{
printf("Have extra arguments: ");
for (int i = optind; i < argc; ++i)
printf("%s ", argv[i]);
printf("\n");
}
to list all non-option arguments.