-1

The programm should be able to open a file like myFile.txt, alltough it's real name is myFile without the extension .txt. So I wrote the function called removeFileExtension() in order to achieve that.

It does open my file by copying the string from text into filename:

strcpy(filename,text);
FILE *fp = fopen(filename, "r");

So I tried to check what the difference between text and my processed string from removeFileExtension is.

To check if it even works I mate a function called strComparison(), which returns either 0 when it is qual or 1 if unequal. The thing is, after removing the file extension, it shows that both strings are qual, but I am still not able to open the file.

When I type in ./a.out myFile.txt my comparison function returns 0, it is equal, but fopen() still is not able to open the file, respectively I allways get a Segmentation fault.

Does anyone see the problem here? Why am I getting a Segmentation fault?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void removeFileExtension(char *haystack);
int strComparison(char *one, char *two);

int main(int argc, char const *argv[])
{
  //----------------------------------------------------------------------------
  // CHECK INPUT VALIDITY
  //
  if (argc != 2)
  {
    printf("Usage: ./ass2 [file-name]\n");
    return 1;
  }


  //----------------------------------------------------------------------------
  // OPEN FILE (INITIAL)
  //
  char filename[32];
  strcpy(filename, argv[1]);
  FILE *fp = fopen(filename, "r");                                       //FOPEN
  //FILE *fp = fopen("start_of_story\0txt", "r");   // this way does work
  if (fp == NULL)
  {
    // IF NOT FOUND: REMOVE EXTENSION
    removeFileExtension(filename);
    char text[] = "myFile\0";
    int ret_val = -1;
    ret_val = strComparison(filename, text);
    if (ret_val == 0)
      printf("[DEBUG] equal\n");
    else
      printf("[DEBUG] unequal\n");

    printf("[DEBUG] ret_val: %d\n", ret_val);
    printf("[DEBUG] '%s'\n", filename);
    FILE *fp = fopen(filename, "r");                                     //FOPEN

    // IF STILL DOESN'T WORK: ERROR
    if (fp == NULL)
    {
      printf("[ERR] Could not read file %s.\n", filename);
      return 3;
    }
  }


  //--------------------------------------------------------------------------
  // READ DATA (INITIAL)
  //
  int bufsize = 1024;
  char *buffer = malloc(bufsize * sizeof(char));                      //MALLOC
  if (!buffer)
  {
    printf("[ERR] Out of memory.\n");
    return 2;
  }
  fseek(fp, 0, SEEK_SET);
  fread(buffer, bufsize, 1, fp);

  printf("[DEBUG] %s\n", buffer);
  fclose(fp);                                                           //FCLOSE

  free(buffer);
  buffer = NULL;
  return 0;
}

void removeFileExtension(char *haystack)
{
  char needle[1] = ".";
  char *retp;   // return pointer
  retp = strstr(haystack,needle);
  if (*retp == '.')
  {
    while (*retp != '\0')
    {
      *retp++ = '\0';
    }
    printf("[DEBUG] %s\n", haystack);
  }
}

int strComparison(char *one, char *two)
{
  do
  {
    printf("[DEBUG] '%c' == '%c'\n", *one, *two);
    if (*one++ != *two++)
    {
      return 1; // return 1 if unqual
    }
  }
  while ( (*one != '\0') || (*two != '\0') );
  return 0; // return 0 if qual
}

Resulting output:

user@host ~/Desktop $ ./a.out myFile.txt
[DEBUG] myFile
[DEBUG] 'm' == 'm'
[DEBUG] 'y' == 'y'
[DEBUG] 'F' == 'F'
[DEBUG] 'i' == 'i'
[DEBUG] 'l' == 'l'
[DEBUG] 'e' == 'e'
[DEBUG] equal
[DEBUG] ret_val: 0
[DEBUG] 'myFile'
[ERR] Could not read file myFile.
user@host ~/Desktop $
PatrickSteiner
  • 495
  • 4
  • 26
  • 1
    Warning: `char needle[1] = "."` is not a _string_. – Sourav Ghosh Dec 04 '17 at 09:29
  • 1
    Where are you getting the SegFault? Run your code in a debugger like gdb to find out as that is vital and valuable information in a question like this – Chris Turner Dec 04 '17 at 09:33
  • as @SouravGhosh said, using strstr on needle will give you a segmentation fault, as "." gets translated to 2 chars, including '\0' as the second char – Shlomi Agiv Dec 04 '17 at 09:37
  • 1
    Why are you *copying* the filename around?! Just use `argv[1]` in call to `fopen` and be done with it. It is even allowed to mutate `argv[1]`, for example to make it *shorter*. – Antti Haapala -- Слава Україні Dec 04 '17 at 09:39
  • also check your file system. It seems from your description like "start_of_story" exists, but "myFile" doesn't – Shlomi Agiv Dec 04 '17 at 09:40
  • 1
    So you are writing (possibly faulty) check functions to check whether you have implemented a function without faults? Smells like you need to learn to use a debugger! – Paul Ogilvie Dec 04 '17 at 09:40
  • `while ( (*one != '\0') || (*two != '\0') );` You access the shorter string beyond the `\0` byte. Why don't you simply use `strcmp` instead of writing your own comparison function? – Gerhardh Dec 04 '17 at 09:43
  • @Gerhardh I tried it with `strcmp()`, same result, it returns `0`, meaning that both are equal! – PatrickSteiner Dec 04 '17 at 09:59
  • But `strcmp` would not access any string beyond its terminating 0 byte. – Gerhardh Dec 04 '17 at 10:13
  • Why would you write `char text[] = "myFile\0";` when strings in C are already null-terminated? Please compile with `-Wall` and `-Wextra` for gods sake – Erik W Dec 04 '17 at 10:41

2 Answers2

1

Quoting C11, chapter 7.24.5.7

char *strstr(const char *s1, const char *s2);

The strstr function locates the first occurrence in the string pointed to by s1 of the sequence of characters (excluding the terminating null character) in the string pointed to by s2.

So, both the arguments passed to strstr has to be strings. In your case,

 char needle[1] = ".";

is not a string. You did not allow the space for the null-terminator. Either use

  • char needle[2] = ".";, at least, or,
  • char needle[ ] = ".";, or,
  • char const* needle = ".";

As a side effect, whenever the call to removeFileExtension() is reached, you'll face with undefined behavior

That said, beware!!

You are doing something like

retp = strstr(haystack,needle);
  if (*retp == '.')

i.e., dereferencing the returned pointer from strstr(). If, strstr() returns a NULL pointer, you'll again be trapped in UB.


EDIT:

For those who still has confusion about string, check definition in chapter §7.1.1 (emphasis mine)

A string is a contiguous sequence of characters terminated by and including the first null character. [...]

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • Or `char const* needle = ".";` – Michael Burr Dec 04 '17 at 09:40
  • @SouravGhosh According to your suggestion, I tried it with `char needle[2] = ".";` and `char needle[ ] = ".";, or,` and `char const* needle = ".";`. It still produces a `Segmentation fault.` In case of a returned NULL pointer I made a interception-statement: if(!retp){return -1;} and therefore its now a `int`-function, instead a `void`. – PatrickSteiner Dec 04 '17 at 10:15
  • @PatrickSteiner Where do you get the segmentation fault? The UB in your compare function might well cause a segmentation fault. – Gerhardh Dec 04 '17 at 11:25
1

At least I found the problem:
After removing the file's extension, I am still trying to open the old file pointer fp, which gave me the NULL-pointer back. The new file pointer inside the body of the if(fp == NULL){...} only exists inside the scope of the if-statement.

So I created a test_pointer, which first looks if the file even exists, if not, he removes the extension. Than I try again to open the file, this time with fp.

Thanks to everybody for the hints, especially to Sourav Ghosh for your improvement suggestions!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int removeFileExtension(char *haystack);

int main(int argc, char const *argv[])
{
  char filename[64];
  strcpy(filename, argv[1]);


  //----------------------------------------------------------------------------
  // CHECK INPUT VALIDITY
  //
  if (argc != 2)
  {
    printf("Usage: ./ass2 [file-name]\n");
    return 1;
  }


  //----------------------------------------------------------------------------
  // CHECK FILE EXISTENSE
  //
  FILE *test_pointer = fopen(filename, "r");                             //FOPEN
  if (test_pointer == NULL)   // if not found: remove extension
  {
    int ret_val = removeFileExtension(filename);
    if (ret_val == -1)
    {
      printf("[ERR] Could not remove file extension.\n");
      return 3;
    }
  }


  //----------------------------------------------------------------------------
  // OPEN FILE (INITIAL)
  //
  FILE *fp = fopen(filename, "r");                                       //FOPEN
  if (fp == NULL)   // if still doesn't work: error
  {
    printf("[ERR] Could not read file %s.\n", filename);
    return 3;
  }


  //----------------------------------------------------------------------------
  // READ DATA (INITIAL)
  //
  int bufsize = 1024;
  char *buffer = malloc(bufsize * sizeof(char));                        //MALLOC
  if (!buffer)
  {
    printf("[ERR] Out of memory.\n");
    return 2;
  }
  fseek(fp, 0, SEEK_SET);
  fread(buffer, bufsize, 1, fp);
  fclose(fp);                                                           //FCLOSE

  printf("[DEBUG] %s\n", buffer);
  free(buffer);                                                           //FREE
  buffer = NULL;
  return 0;
}


int removeFileExtension(char *haystack)
{
  char needle[] = ".";
  char *retp;   // return pointer
  retp = strstr(haystack,needle);
  if(!retp)     // to prevent UB
    return -1;

  if (*retp == '.')
  {
    while (*retp != '\0')
    {
      *retp++ = '\0';
    }
    printf("[DEBUG] %s\n", haystack);
  }
  return 0;
}
PatrickSteiner
  • 495
  • 4
  • 26