-2

I've seen a few examples of returning array from function on stackoverflow. I followed those examples but i am still getting warnings.

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

char * getNum();

int main(){

    int * num;
    int * i;

    num = getNum();
    puts(num);

    return 0;
}

char * getNum(){

    FILE * fp;
    fp = fopen("number", "r");      //getting a 1000 digit number from a file
    char * n;                       //putting it in "array"
    n = (char *)malloc(1000 * sizeof(char));
    char x[100];
    int i, j = 0;

    while(!feof(fp)){
        fgets(x, 100, fp);
        for(i=0; i<50; i++){        //getting the first 50 characters in a line
            n[j] = x[i];            //to avoid "new line"
            j++;
        }
    }
    fclose(fp);
    n[1000] = '\0';

    return n;
}

puts(num) gives the right number should I just ignore the warnings? Why are they popping up? I hope this isn't considered a duplicat.

cc     8.c   -o 8
8.c: In function ‘main’:
8.c:11:9: warning: assignment from incompatible pointer type
     num = getNum();
         ^
8.c:12:10: warning: passing argument 1 of ‘puts’ from incompatible pointer type
     puts(num);
          ^
In file included from 8.c:1:0:
/usr/include/stdio.h:695:12: note: expected ‘const char *’ but argument is of type ‘int *’
 extern int puts (const char *__s);
            ^
Soto
  • 17
  • 2
  • 2
    What warning are you getting? – haccks Dec 16 '16 at 18:23
  • 2
    Please note that: `feof(fp)` is not a good way to check if there is nothing else to read because `fgets()` needs to fail first (to attempt a read after `EOF`) so you still do the `for (i ...)` loop after the bad read. You should change to `while (fget(x, 100, fp) != NULL)`. – Iharob Al Asimi Dec 16 '16 at 18:24
  • 3
    `n = (char *)malloc(1000 * sizeof(char));` allocates memory for exactly 1000 characters. `n[1000] = '\0';` tries to access the 1001st (!) character. Remember, the array indices start from zero. – ForceBru Dec 16 '16 at 18:26
  • @ForceBru The compiler can't warn about that but you just did. – Iharob Al Asimi Dec 16 '16 at 18:26
  • @Soto I am sorry, it's not my intention to make you feel sorry. I just think that you should read the warning and try to interpret it and find in it sense, that would help you understand many things. – Iharob Al Asimi Dec 16 '16 at 18:36
  • @iharob I tryed reading from a file for the first time and returning array for the first time so when i got a warning i tought i did something wrong there and didn't notice int. – Soto Dec 16 '16 at 18:41
  • 2
    @Soto BTW you are not returning an array, that would be very different and it would be a problem. You are using `malloc()` which means you can return the pointer, but you should check the return value for `NULL` before reading the data into it. Please read my answer for the comment about `while (!feof())` which is going to make your program behave strangely. It's of course natural to think of that algorithmically speaking, but if you read the documentation for `feof()` you would see that it's wrong to write such code. – Iharob Al Asimi Dec 16 '16 at 18:43
  • Note that [`while (!feof(file))` is always wrong](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong). – Jonathan Leffler Dec 16 '16 at 19:36

3 Answers3

5

The problem is that you seem to be assigning the result of calling getNum to a variable of type int *, which doesn't make much sense as getNum returns a char *.

You also try to print with puts that variable of type int *, while puts accepts only a const char *.

What's more, you're getting out of bounds in your function's code, as I've already mentioned in the comments: n = (char *)malloc(1000 * sizeof(char)); allocates memory for exactly 1000 characters. n[1000] = '\0'; tries to access the 1001st (!) character. Remember, the array indices start from zero!

ForceBru
  • 43,482
  • 10
  • 63
  • 98
3
n = (char *)malloc(1000 * sizeof(char)); // ugly code

That should really be

 n = malloc(1000);
 if (n==NULL) {perror("malloc"); exit(EXIT_FAILURE);};

because sizeof(char) is always 1, and because you should not cast (in C) the result of malloc, and because malloc can fail and you should test against that.

Then you do later

   n[1000] = '\0'; // wrong code

This changes the 1001-th byte (not the last 1000-th one), so is undefined behavior (it is a buffer overflow). You should be really scared, bad things could happen (and if they don't, it is because you are unlucky). You probably want

 n[999] = '\0'; // the 1000th byte

BTW, I guess you are using GCC or Clang on some POSIX like system. You really should take the habit of compiling with all warnings and debug info:

cc   -Wall -g  8.c   -o 8

(If using make you probably want CFLAGS= -Wall -g in your Makefile)

You might want to learn more about instrumentation options, e.g. you could also pass -fsanitize=address to gcc

Then you can use the gdb debugger and perhaps also valgrind. But be sure to improve your own code till you get no warnings.

Of course num = getNum(); is incorrect. You are assigning a pointer into an integer (so you have a type mismatch). That is often wrong (and in the rare cases -not here- you would really mean it, you should have some explicit cast to show to the reader of your code - perhaps you next year - what you really wanted to do).

You want to convert a string to a number. Read more the documentation of the C standard library. You want to use atoi (type man atoi in a terminal, or read atoi(3)) then code:

num = atoi(getNum());

You are also coding:

while(!feof(fp)) // bad code

This is wrong (and a bit tricky, see this). feof is only valid after some read operation (and not before, see feof(3)). since you want to remove the ending \n (but read fgets(3) & strchr(3)...) you probably want instead

 do {
   if (NULL==fgets(x, 100, fp)) break;
   char*eol = strchr(x, '\n');
   if (eol) *eol = 0;
 } while (!feof(fp));

at last your code is also incorrect because malloc is not initializing the returned memory zone. So your n might have a zero byte in some unexpected place.

Perhaps you should read about the (POSIX specific) strdup(3) or getline(3). Both could make your code simpler. And think about the adverse situation of files with very long lines (you might have a file with a line of many thousand bytes, and you could even have a file without any newlines in it).

Your puts(num) is also wrong, since also a type mismatch. Consider using printf(3) (but take the habit of ending the control format string with \n or else use fflush(3) because <stdio.h> is buffering), so printf("%d\n", num);

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
2

The problem is that you are assigning a pointer of type char * to one of type int *, hence "INCOMPATIBLE" pointers.

You also attempted to pass the int * pointer to puts() which expects a char * pointer, thus there is another warning.

Why are you doing this? If they are clearly pointers of different type it's very strange that you attempted it anyway.

It would be interesting to know, if you think this is correct for some reason.

You need to carefully read warnings and try to understand what they mean, it would help you learn a lot of the basics and good practice too.

Also, please note that: while (!feof(fp)) is not a good way to check if there is nothing else to read because fgets() needs to fail first (to attempt a read after EOF) so you still do the for (i ...) loop after the bad read. You should change to while (fget(x, 100, fp) != NULL)

Finally, in there is no need to cast void * to any other poitner type, and it's considered bad practice to cast the return value of malloc() because of the reasons explained in this answer

Community
  • 1
  • 1
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • I think they downvoted because they considered that it was rude. But, it was not my intention. I understand that you are learning and all, but it doesn't mean that you should be excused for not understanding the warning message, I understand that not everyone can interpret it and the lack of information might be a good explanation, but you have to try. I am glad to help. – Iharob Al Asimi Dec 16 '16 at 19:05
  • Maybe it would be helpful to add a link to [the ubiquitous post about using `feof()`](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) to control loops. – ad absurdum Dec 16 '16 at 19:18
  • @iharob I think they downvoted because I said I was sorry. But i wasn't really sorry i was manipulating you into answering despite thinking that the answer is obvious :) (after a few years running arch linux i always asume people on forums won't answer if they think question is stupid). But i saw that it wasn't necessary because people here are nice and helpful. Also you may not realise how little i know about programing i just learnt basic syntex and then i looked on forums for what to do next. So i have been solving problems on project euler and this is part of problem eight. – Soto Dec 16 '16 at 19:45
  • We are distro brothers! yes, adding huge numbers was it? Project euler, had a lot of fun with it too. – Iharob Al Asimi Dec 16 '16 at 19:59
  • Largest product of 13 adjacent digits in 1000-digit number. – Soto Dec 16 '16 at 20:12
  • @iharob I changed from while (!feof(fp)) to while (fgets(x, 100, fp) != NULL) and the first line isn't read so iswitched whlie loop to do while loop and now the second line isn't read. What should i do. – Soto Dec 18 '16 at 16:36
  • Check *getting first 50 ...*, because that's the wrong way to do it!!!!! Instead, use `strlen()` to determine the length and remove the last character **if** it's the `'\n'`, if ti's not your line is too short. Or, try something like `size_t i; for (i = 0 ; ((line[i] != '\0') && (line[i] != '\n')) ; ++i); line[i] = '\0';` to remove the end of line character and calculate the length "*simultaneously*". – Iharob Al Asimi Dec 18 '16 at 17:54
  • `do{ fgets(x, 100, fp); size_t i; for (i = 0 ; ((x[i] != '\0') && (x[i] != '\n')) ; ++i){ n[j] = x[i]; j++; } }while (fgets(x, 100, fp) != NULL);` my code now i still have the problem – Soto Dec 18 '16 at 19:49
  • The point is to check `fgets()`'s result, otherwise the same problem explained above! Also, you could ask a new question explaining it in detail and posting the code. – Iharob Al Asimi Dec 18 '16 at 20:43
  • Sorry to bother you again this is my last question and I don't think it is enough for a 'new question'. I did an inifite do-while loop for reading. After the fgetc in the loop i put if(feop(fp)) {break;}. Is this still a bad code or is it good? – Soto Dec 18 '16 at 23:27