0

I've written a program to reverse a .txt file, line-by-line, and return the output to a new file. It is part of the requirements for the command line arguments to NOT include the .txt extension, so I add in at the top of the program before fopen is called on the file. This works perfectly fine in macOSx terminal, as you can see here: https://i.stack.imgur.com/PHugj.jpg

However, when I upload this to my school's server, I get the following output: https://i.stack.imgur.com/SLygw.jpg

Relevant code:

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

#define NUMARG 3
#define INFILEARG 1
#define OUTFILEARG 2

int countWords(const char *sentence);

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

    /* File pointers */
    FILE *finp;
    FILE *foutp;

    /* Three levels of strings: word < line < text. 
       Both token variables to use with strtok splitting the text. */
    char **holdWords = NULL, *holdLine = NULL, *holdText = NULL,
             *lineToken = NULL, *wordToken = NULL;
    int stringSize = 0, totalStrings, i;
    size_t size = 0;

    /* Add .txt extension */
    int inFileNameSize = sizeof(argv[INFILEARG]);
    int outFileNameSize = sizeof(argv[OUTFILEARG]);

    char inFileName[inFileNameSize+4]; //add 4 to have room for ".txt"
    char outFileName[outFileNameSize+4];

    strcat(inFileName, argv[INFILEARG]);
    strcat(inFileName, ".txt");
    strcat(outFileName, argv[OUTFILEARG]);
    strcat(outFileName, ".txt");

    /* Check for errors in argument number and opening files. */
    if(argc != NUMARG){
            printf("You have to put the input and output files after the program name.\n"); fflush(stdout);
            return(1);
    }

    if( (finp = fopen(inFileName, "r")) == NULL ){
            printf("Couldn't open %s for reading.\n", inFileName); fflush(stdout);
            return(1);
    }

    if( (foutp = fopen(outFileName, "w")) == NULL){
            printf("Couldn't open %s for writing.\n", outFileName); fflush(stdout);
            return(1);
    }

Can anyone help me figure out what's going on here? Thank you.

EDIT TO EXPLAIN WHY DIFFERENT THAN LINKED QUESTION: While it's helpful to know why a pointer to an array can't be sizeof'd, my question is about getting the size of a string (one pointer, not a pointer to a pointer). I get an error when using strlen on my mac, yet it works on unix. I get an error when using sizeof of the unix, yet sizeof works on my mac.

  • 3
    `sizeof(argv[INFILEARG])` - um. that's the size of a *pointer*. If you want the length of a string use `strlen`. Likewize for `sizeof(argv[OUTFILEARG])` Your program also invokes undefined behavior because you invoke `strcat` on target buffers that are *not* guaranteed to contain a terminating nullchar. Neither `inFileName` nor `outFileName` are initialized. At least the first part of each should be `strcpy`-ed, – WhozCraig Oct 19 '17 at 22:16
  • Recall the declaration for `main`, e.g ..`char *argv[]` (that is an *array of pointers*). – David C. Rankin Oct 19 '17 at 22:18
  • Whoa, cool. Thank you. So, am I using sizeof correctly when I malloc in the following example?: char **holdText = malloc((size + 1) * sizeof(*holdText)); – Zachary Sedefian Oct 19 '17 at 22:21
  • @ZacharySedefian `sizeof` operator returns you the size of that object and not its length, use `strlen()`. – Michi Oct 19 '17 at 22:22
  • @Michi I don't believe you are correct if you were responding to my comment and not the original post. – Zachary Sedefian Oct 19 '17 at 22:26
  • @ZacharySedefian I will not use realloc on the same pointer, but if you insist: `char **holdWords = realloc ( holdWords, totalStrings1 * sizeof(*holdWords) );` – Michi Oct 19 '17 at 22:34
  • @Michi It's inside a loop so it needs to be allocated each time. – Zachary Sedefian Oct 19 '17 at 22:35
  • @ZacharySedefian What's exactly your problem? You are showing us a code and you ask a Question about it and now you come with this, why? – Michi Oct 19 '17 at 22:37
  • 1
    Possible duplicate of [How to find the 'sizeof' (a pointer pointing to an array)?](https://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array) – n. m. could be an AI Oct 19 '17 at 22:38
  • Also you cannot `strcat` to a character array that wasn't initialised, so `strcat(inFileName, argv[INFILEARG]);` is undefined behaviour. – n. m. could be an AI Oct 19 '17 at 22:45
  • @n.m. Was it not initialized on the line char inFileName[inFileNameSize+4];? – Zachary Sedefian Oct 19 '17 at 22:54
  • @ZacharySedefian Get a **C** Book please. – Michi Oct 19 '17 at 22:58
  • No it was not. Why would you think it was? It is only declared on that line, not initialised. – n. m. could be an AI Oct 19 '17 at 23:11
  • @n.m. Okay, so I suppose this initializes it. I was completely mistaken before. char *inFileName = malloc(sizeof(char) * (inFileNameSize+4)); – Zachary Sedefian Oct 19 '17 at 23:17
  • A character array have to contain a null-terminated string before you can use `strcat` on it. `strcpy` is one way to make ensure that. You can replace the first and third `strcat` with `strcpy`. – n. m. could be an AI Oct 19 '17 at 23:22
  • No, `mallloc` doesn't initialise anything. It may work for you by sheer chance but you shouldn't rely on it. – n. m. could be an AI Oct 19 '17 at 23:24
  • @n.m. So, strcpy initializes a string? How would I initialize it if I happened to not want to use strcpy? – Zachary Sedefian Oct 19 '17 at 23:29

1 Answers1

1

It appears your have a buffer overflow, you can see this by the fact the file names printed appear corrupted.

If you look at the lines:

/* Add .txt extension */
int inFileNameSize = sizeof(argv[INFILEARG]);
int outFileNameSize = sizeof(argv[OUTFILEARG]);

Your error lies in the use of the sizeof operator. This returns the sizeof the type not the length of the string. Hence your in/outFileNameSize variable is too short for the actual string you are copying into it.

Benjamin Close
  • 311
  • 1
  • 8
  • Okay, that works on the unix machine. But I get this on my mac: ./p2.o file1 file2 Couldn't open ??R?file1.txt for reading. – Zachary Sedefian Oct 19 '17 at 22:31
  • @ZacharySedefian start with: **1)** how to check main arguments in C first. **2)** After that, use the code to extend it to, how to open a file in C based of main arguments (after you do a check) . **3)** Latter make another code about how to check a file if exists in C **4)** if exists that file then how to open it **5)** then how to read that file. – Michi Oct 19 '17 at 22:43