1

So I have a function called scanCode which scans words from a text file and stores it in a 2D array. I then want to return this array into an array variable in the main function, this is my code so far

#include <stdio.h>

char **scanCode()
{
    FILE *in_file;
    int i = 0;
    static char scan[9054][6];

    in_file = fopen("message.txt", "r");
    while (!feof(in_file))
    {

        fscanf(in_file, "%s", scan[i]);
        i++;
    }
    return scan;
}

int main(void)
{

    int hi[9053];

    FILE *in_file;

    in_file = fopen("message.txt", "r");

    char **array = scanCode();

    printf("%c", array[0]);
    printf("%c", array[1]);
    printf("%c", array[2]);
    printf("%c", array[3]);
}

So basically the array returned from the scanCode function I want it to be stored in the char array in the main function.. after looking at a lot of questions and answers here, this is what I got to but the pointer etc is hard to understand for me.. could someone tell me what I did wrong here?

lurker
  • 56,987
  • 9
  • 69
  • 103
anony
  • 79
  • 1
  • 2
  • 10
  • Why are you using `%c` to print a string, `array[n]`? – lurker Dec 04 '15 at 17:27
  • well when i put %s, the cmd run window freezes so there is sometihng wrong with the array – anony Dec 04 '15 at 17:31
  • Using the wrong format specifier isn't going to fix the problem with the array. ;) Do you have any strings in your `message.txt` file that are longer than 5 characters? And why did you open the file twice (once in `main` and once in the function)? That's a bad idea. – lurker Dec 04 '15 at 17:33
  • nope, not a single because if i just simply use the whole scanCode lines in the main function it all works fine. its just when i try to seperate them into functions.. all the words max size is 5 letters. i understand, but i didnt know whether %s or %c was right since %s is not accepted in my case – anony Dec 04 '15 at 17:35
  • Well at the very least, you don't want two `fopen` on the same file before a close. And when you compile, did you see a warning on `return scan` for incompatible pointer type? The warning actually means something. `char scan[][]` and `char **scan` are not the same type. – lurker Dec 04 '15 at 17:36
  • 1
    One other point: `while (!feof(in_file))` is a bad way to read until end of file. `feof` will only be true on an attempt to *read beyond* end of file, so your code will attempt an additional `fscanf` after the last line of the file has already been read, and you'll have one bogus entry at the end of your scan array. See [Why is “while ( !feof (file) )” always wrong?](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). – lurker Dec 04 '15 at 17:46
  • 1
    @lurker OP has had 3 replies in previous answers to not use `while (feof() ...` Perhaps this 4th one will do the trick. – chux - Reinstate Monica Dec 04 '15 at 17:56
  • @chux youve got the wrong impression ive worked on every answer ive got so far and every question i have put up have been solved so far, i just didnt know about upvoting answers or how to change the question to solved, sorry – anony Dec 04 '15 at 18:59
  • Consider taking the [tour](http://stackoverflow.com/tour) – chux - Reinstate Monica Dec 04 '15 at 19:04
  • oh yeah i also didnt change the feof part even though i understand why it was wrong because my teacher taught us how to deal with this problem using feof, so i wanted to be safe by using feof to guarantee the marks – anony Dec 04 '15 at 19:07

3 Answers3

4

Change the return type of the function the following way

#include <stdio.h>

char ( *scanCode() )[6]
{
    FILE *in_file;
    int i = 0;
    static char scan[9054][6];

    in_file = fopen("message.txt", "r");
    while (!feof(in_file))
    {

        fscanf(in_file, "%s", scan[i]);
        i++;
    }
    return scan;
}

int main(void)
{

    int hi[9053];

    FILE *in_file;

    in_file = fopen("message.txt", "r");

    char ( *array )[6] = scanCode();

    printf("%s", array[0]);
    printf("%s", array[1]);
    printf("%s", array[2]);
    printf("%s", array[3]);
}

Also in the printf statements use format specifier %s

And change the loop in the function like

    while ( i < 9054 && fscanf(in_file, "%5s", scan[i]) == 1 ) ++i;
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

I prefer to simplify the code in this way:

#include <stdio.h>

#define NumLines   9054
#define NumCols    6

void freeMem(char **ele) {
    while (*ele != NULL) {
        free(*ele);
        ele++;
    }
}

char **scanCode(char *fileName)
{
    FILE *in_file;
    char readingFormat[128];
    int i = 0;

    /*
     * Instead to declare a static variable I prefer to allocate dynamically
     * the bidimensional array.
     * It is done in two steps:
     * 1. allocate the memory for the first dimension
     * 2. for each element in this dimension allocate the memory for each element in the second dimension
     *
    */
    char **scan = (char **)malloc((NumLines + 1) * sizeof(char *));
    if (scan == NULL) {
        return NULL;
    }
    for (int j = 0; j < NumLines; j++) {
        scan[j] = (char *)malloc(NumCols + 1);
        if (scan[j] == NULL) {
            freeMem(scan);
            return NULL;
        }
        scan[j][0] = NULL;
    }
    scan[NumLines] = NULL;  // define the end of memory

    in_file = fopen(fileName, "r");
    if (fopen == NULL) {
        freeMem(scan);
        return NULL;
    }
    sprintf(readingFormat, "%%%ds", NumCols);
    while (fscanf(in_file, readingFormat, scan[i]) == 1 && i < NumLines) {
        i++;
    }
    return scan;
}

int main(void)
{
    char **array = scanCode("message.txt");
    if (array == NULL) {
        printf("ERROR\n");
        exit(0);
    }
    for (char **tp = array; **tp != NULL; tp++) {
        printf("%s\n", *tp);
    }
}
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
  • 1
    I personally prefer to pass the file name as a parameter. You should get rid of the magic numbers (9054?) and check directly the scanf() not the foef(). – Bob__ Dec 04 '15 at 17:59
  • 1
    This is a sensible approach (+1), although I would probably just use `malloc(6)` in place of `malloc(6 * sizeof(char))` since `sizeof(char)` is well-understood (this is the only exception I generally make to explicitly indicating a `sizeof`). Also, I know in this case since `main` just exits, it's worth noting that the caller to `scanCode()` needs to be responsible for freeing the memory for the return pointer once it's no longer needed. I also agree with the improvements suggested by @Bob__. – lurker Dec 04 '15 at 18:00
  • `fscanf(in_file, "%s", scan[i]);` is just as safe as `gets(scan[i])`. Consider adding a limitation on input length. – chux - Reinstate Monica Dec 04 '15 at 18:04
  • 1
    I certainly don't think this is the best idea. You should avoid using 'malloc' as much as you can. – AnArrayOfFunctions Dec 04 '15 at 18:27
  • @FISOCPP why should `malloc` be avoided as much as one can? – lurker Dec 04 '15 at 18:36
  • Well because it's slow compared to creating a local. And also you should not forget to deallocate the memory with 'free'. – AnArrayOfFunctions Dec 04 '15 at 18:49
  • Better ;), but exit(0) means EXIT_SUCCESS, you should call freeMem before exit and add fre(ele)... – Bob__ Dec 04 '15 at 19:39
1

Arrays aren't pointers (hello from me again).

This:

static char scan[9054][6];

have the most obvious type you would expect it to be - 'char [9054][6]' and not 'char **'. It's spelled as an array of 6 elements each of which is another array of 9054 chars. On the other hand the type 'char **' is spelled as 'a pointer to pointer to char' and as you can probably see now they are entirely different things.

Your code should look something like this:

#include <stdio.h>

typedef char yourArrayType[9054][6];

typedef struct { yourArrayType return_value; } letsReturnArraysType;

letsReturnArraysType scanCode()
{
    FILE *in_file;
    int i = 0;
    yourArrayType scan;

    in_file = fopen("message.txt", "r");
    while (!feof(in_file))
    {

        fscanf(in_file, "%s", scan[i]);
        i++;
    }
    return *(letsReturnArraysType*)scan;
}

int main(void)
{

    int hi[9053];

    FILE *in_file;

    in_file = fopen("message.txt", "r");

    letsReturnArraysType arrayStruct = scanCode();

    printf("%s", arrayStruct.return_value[0]);
    printf("%s", arrayStruct.return_value[1]);
    printf("%s", arrayStruct.return_value[2]);
    printf("%s", arrayStruct.return_value[3]);
}
AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • No as I'm returning the whole array. – AnArrayOfFunctions Dec 04 '15 at 18:16
  • I see. But not very efficient for a large array. Internally, the compiler generates a `memcpy` to make a whole new copy of the array for the return. – lurker Dec 04 '15 at 18:17
  • Well yeah you're right. But my point was rather educational then efficient. About your last statement - yeah if your compiler is crap but most recent compilers will certainly optimize it. I guess they'll treat my local 'scan' as directly the return-value itself or maybe even the local in main 'arrayStruct'. – AnArrayOfFunctions Dec 04 '15 at 18:21