1

I wrote a program that scans an unknown amount of integers into an array but when I run it, it print the last value it has gotten an infinite amount of times.

For example for the input: 1 2 3 4 5

The output would be 55555555555555555555555...

Why does this happen and how can I fix that?

My goal here is to create a array, for an instance {1, 2, 3, 4, 5} and then print what it scanned into the array, ONLY ONCE...

int *pSet = (int*) malloc(sizeof(int)); int i; int c;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");

scanf("%d", &c);
pSet[0] = c;
printf("%d ", c);
for(i = 1; c != EOF; i++) {
    pSet = (int*) realloc(pSet, sizeof(int)*(i+1));
    if(pSet == NULL) {
        return FAIL;        
    }
    scanf("%d", &c);
    pSet[i] = c;
    printf("%d ", c);
}

free(pSet);
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • 2
    You never check if `scanf()` actually works. – Andrew Henle Nov 30 '18 at 17:09
  • I tried to fix my input according to what you sent but it doesn't change anything. I sent to the program: 1 2 3 4 5 (Enter) (Enter) @BurnsBA – Shadow OverLoad Nov 30 '18 at 17:11
  • If scanf() didn't work the variable c wouldn't have been initialized. The program print c, and at the time of printing c is 5. I hardly think this is the issue... But thanks anyways! @AndrewHenle – Shadow OverLoad Nov 30 '18 at 17:13
  • 2
    A problem in this few a lines of mostly self-contained code is *born* to be single-stepped in a *debugger*. And stop ignoring the results of those `scanf` calls, lest you violate [Spencer's Sixth Commandment](http://www.seebs.net/c/10com.html). Finally, I challenge you to point out where, in the [documentation for `scanf`](https://en.cppreference.com/w/c/io/fscanf), it states it populates integer-formatted output arguments with `EOF` once the stream hits said-same (because no such behavior exists). Short version: *Read and understand the requirements of the functions you're using*. – WhozCraig Nov 30 '18 at 17:16
  • Unnecessary "[not solved]" title edit removed. Solved or not solved, the title need not change. – chux - Reinstate Monica Nov 30 '18 at 18:26
  • How do you want to indicate that you are done inputting numbers? – chux - Reinstate Monica Nov 30 '18 at 18:48

3 Answers3

2

Why does this happen (?) (print ... an infinite amount of times.)

Look at the loop terminating conditions c != EOF.

int c;
scanf("%d", &c);
for(i = 1; c != EOF; i++) {  // Not good code
  scanf("%d", &c);
}

EOF is some negative value, often -1. scanf("%d", &c) attempts to read user input and convert to an int. scanf() returns a 1,0,EOF depending on if it 1) succeeded, 2) failed to find numeric text or 3) end-of-file or input error occurred. Unfortunately code does not use that return value. Instead code used the number read, c and checked if that number read was the same as EOF.


how can I fix that?

Only loop when the return value of scanf() is as expected (1).

for(i = 1; scanf("%d", &c) == 1; i++) {
  ...
}

Putting this together with some other ideas

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

int main(void) {
  printf("Please enter a stream of numbers to make a set out of them:\n");
  int *pSet = NULL;  // Start with no allocation
  size_t i = 0;

  int c;
  for (i = 0; scanf("%d", &c) == 1; i++) {
    //        +---------------------------  No cast needed.
    //        v               v----------v  Use sizeof de-referenced pointer
    void *p =   realloc(pSet, sizeof *pSet * (i + 1));
    if (p == NULL) {
      free(pSet);
      return EXIT_FAILURE;
    }
    pSet = p;
    pSet[i] = c;
  }

  for (size_t j = 0; j < i; j++) {
    printf("%d ", pSet[j]);
  }

  free(pSet);
  return 0;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

You should stop your loop when scanf fails. According to the manual:

On success, [scanf] return[s] the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure. The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs. [...]

So you can turn your for loop into a while one.

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

#define FAIL 0
int main() {
  int *pSet = (int*) malloc(sizeof(int));
  int c;
  int i=0;
  printf("Please enter a stream of numbers to make a set out of them: ");
  while(scanf("%d", &c) == 1) {
    pSet[i] = c;
    pSetNew = (int*) realloc(pSet, sizeof(int)*(i+1));
    if(pSetNew == NULL) {
      free(pSet);
      return FAIL;        
    } else {
      pSet = pSetNew;
    }
    printf("%d ", c);
    i++;
  }

  free(pSet);
}

But if you want a more robust piece of code, I suggest you to retrieve the answer as a string (NULL-terminated array of char), and then parse it with dedicated functions like strtol which let you check if the whole string is a valid entry, and not only the first characters.

Note: HengLi fixed a potential memory leak in the code sample above

Amessihel
  • 5,891
  • 3
  • 16
  • 40
  • *** Error in `./catch': realloc(): invalid next size: 0x088c8008 *** @Amessihel – Shadow OverLoad Dec 01 '18 at 14:01
  • @ShadowOverLoad It should be better to search for existing answer related to this issue, or asking a new question describing accurately your environment, to avoid to create a duplicate. – Amessihel Dec 02 '18 at 10:02
  • There is potentially a memory leak problem in the code. When realloc cannot find enough space to allocate, it returns a NULL and keeps the original space allocated. This [example](https://stackoverflow.com/questions/1986538/how-to-handle-realloc-when-it-fails-due-to-memory/1986572#1986572) shows how to fix the problem by using a new variable to hold the return of realloc. – Heng Li Oct 07 '19 at 18:11
1

There are a number of problems.

1) Terminate the loop when scanf fails instead of using EOF. Do that by checking that the return value is 1 (i.e. the number of input items successfully matched)

2) Don't allocate memory until it's needed

3) Never do realloc directly into the target pointer - always use a temp variable.

Fixing this your code could be:

#include <stdio.h>

int main(void) {
    int *pSet = NULL;
    printf("Please enter a stream of numbers to make a set out of them: ");
    printf("\n");

    int i = 0;
    int c;
    while (1) {
         if (scanf("%d", &c) != 1)
         {
             printf("Terminating input loop\n");
             break;
         }

         int* tmp = realloc(pSet, sizeof(int)*(i+1));
         if(tmp == NULL) {
            printf("oh dear...\n");
            break;
         }
         pSet = tmp;
         pSet[i++] = c;
         printf("%d ", c);
    }

    for (int j=0; j < i; ++j) printf("%d\n", pSet[j]);
    free(pSet);
    return 0;
}

Input:

1 2 3 4 5 6 7 stop

Output:

Please enter a stream of numbers to make a set out of them: 
1 2 3 4 5 6 7 
Terminating input loop
1
2
3
4
5
6
7
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • realloc in temp (line 17) fails everytime. @4386427 – Shadow OverLoad Nov 30 '18 at 18:22
  • https://ideone.com/XR4tQt I changed your code, some of the things you wrote are not according to the C syntax. @4386427 – Shadow OverLoad Nov 30 '18 at 18:39
  • 1
    @ShadowOverLoad What did you find specifically that was not "not according to the C syntax"? What current version of C are you using? I suspect it is a 20 years old version. This answer is valid C. – chux - Reinstate Monica Nov 30 '18 at 18:54
  • @ShadowOverLoad " not according to the C syntax" What? Please clarify – Support Ukraine Nov 30 '18 at 19:10
  • I sent the code after fixing it. For example, in C the compiler won't let you define and initialize all at once inside a loop, as you did with the array tmp. @4386427 – Shadow OverLoad Dec 01 '18 at 13:48
  • Besides, realloc fails everytime. For any input the output would be : Please enter a stream of numbers to make a set out of them: oh dear... Segmentation fault (core dumped) @4386427 – Shadow OverLoad Dec 01 '18 at 14:06
  • @ShadowOverLoad You must be using some very old C compiler. And if the `realloc` fails your system is not only old but also buggy. Once again - see here https://ideone.com/HSKTCH – Support Ukraine Dec 01 '18 at 15:34