C : buffer and pointers

Viewed 6792

I'm writing a little program that must:

  1. Ask a user how many numbers he will enter (to stock in 2 tab dynamically)
  2. Enter numbers step by step and the number go in the bufferP if he is positive and in bufferN if negative
  3. If there is no more place in a buffer, double the size of this one
  4. Finally printf both buffers

Here is my code:

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

int main(){
    int length = 0;
    printf("Number of data: \n");
    scanf("%d", &length);
    int *bufferP = (int*)malloc(2*sizeof(int));
    int *bufferN = (int*)malloc(2*sizeof(int));
    int number = 0;
    for (int i = 0 ; i <= length ; i++){
        scanf("%d", &number);
        if(number < 0){
            if(*bufferN == NULL){
                printf("No more place");
                exit(0);
            }
            *bufferN= number;
            *bufferN++;
        }

        if(number >= 0){
            if(*bufferP == NULL){
                printf("No more place");

            }
            *bufferP = number;
            *bufferP++;
        }

    }

    int res =0;
    printf("tab negative : ");
    for (int i = 0; bufferN[i] != NULL; i++)
    {
        res = bufferN[i]; 
        printf("%d\n", res );
    }
    printf("tab positive : ");
    for (int i = 0; bufferP[i] != NULL; i++)
    {
        res = bufferP[i]; 
        printf("%d\n", res );
    }
}

I've got those errors :

 In function ‘main’:
rev_S3_ptr.c:14:16: error: comparison between pointer and integer [-Werror]
    if(*bufferN == NULL){
                ^~
rev_S3_ptr.c:19:4: error: value computed is not used [-Werror=unused-value]
    *bufferN++;
    ^~~~~~~~~~
rev_S3_ptr.c:23:16: error: comparison between pointer and integer [-Werror]
    if(*bufferP == NULL){
                ^~
rev_S3_ptr.c:28:4: error: value computed is not used [-Werror=unused-value]
    *bufferP++;
    ^~~~~~~~~~
rev_S3_ptr.c:35:29: error: comparison between pointer and integer [-Werror]
  for (int i = 0; bufferN[i] != NULL; i++)
                             ^~
rev_S3_ptr.c:41:29: error: comparison between pointer and integer [-Werror]
  for (int i = 0; bufferP[i] != NULL; i++)

So my question are:

  1. The buffer works like a tab right ? So why can't I just say that if the pointer is null it is full and do *buffer ++ ?
  2. At the "No more place" I must double the size of the buffer and I don't know how to do this.
4 Answers

How about this version:

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

int main(){
    int length = 0;
    printf("Number of data: \n");
    scanf("%d", &length);
    int bufferP_size = 2, bufferP_loc = 0;
    int *bufferP = (int*)malloc(bufferP_size*sizeof(int));
    int bufferN_size = 2, bufferN_loc = 0;
    int *bufferN = (int*)malloc(bufferN_size*sizeof(int));
    int number = 0;
    for (int i = 0 ; i <= length ; i++) {
        scanf("%d", &number);
        if(number < 0) {
            if(bufferN_loc == (bufferN_size - 1)) {
                int *temp_buffer;
                printf("No more room in negative buffer, extending\n");
                bufferN_size *= 2; 
                temp_buffer = (int*)realloc(bufferN,bufferN_size*sizeof(int));
                if (temp_buffer == NULL) {
                    printf("Memory allocation failed, aborting\n");
                    free(bufferP);
                    free(bufferN);
                    exit(EXIT_FAILURE);
                }
                bufferN = temp_buffer;
            }
            bufferN[bufferN_loc++] = number;
        }

        if(number >= 0) {
            if(bufferP_loc == (bufferP_size - 1)) {
                int *temp_buffer;
                printf("No more room in positive buffer, extending\n");
                bufferP_size *= 2; 
                temp_buffer = (int*)realloc(bufferP,bufferP_size*sizeof(int));
                if (temp_buffer == NULL) {
                    printf("Memory allocation failed, aborting\n");
                    free(bufferP);
                    free(bufferN);
                    exit(EXIT_FAILURE);
                }
                bufferP = temp_buffer;
            }
            bufferP[bufferP_loc++] = number;
        }
    }

    int res =0;
    printf("tab negative : ");
    for (int i = 0; i < bufferN_loc; i++)
    {
        res = bufferN[i]; 
        printf("%d\n", res );
    }
    printf("tab positive : ");
    for (int i = 0; i < bufferP_loc; i++)
    {
        res = bufferP[i]; 
        printf("%d\n", res );
    }
    free(bufferP);
    free(bufferN);
    exit(EXIT_SUCCESS);
}

The significant changes are:

  • Don't throw away the start of buffer pointers when reading into the buffer
  • realloc is your friend for extending the buffer
  • You can't use the pointer to the buffer to work out when you reach the end of the buffer, you have to keep track of how big it is yourself
  • Store the current position as well as the size of the buffer, so you can track where to read and write from

Consider following changes:

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

int main(){
    int length = 0;
    printf("Number of data: \n");
    scanf("%d", &length);

    int bufferP_cap = 2, bufferN_cap = 2;
    int bufferP_size = 0, bufferN_size = 0;
    int* bufferP = (int*)malloc(bufferP_cap * sizeof(int));
    int* bufferN = (int*)malloc(bufferN_cap * sizeof(int));

    int number = 0;
    for (int i = 0 ; i < length ; i++){  // '<' instead of '<='
        scanf("%d", &number);
        if(number < 0){
            if ( bufferN_size == bufferN_cap){
                bufferN_cap *= 2;
                bufferN = (int*)realloc(bufferN, sizeof(int)*bufferN_cap);
            }
            bufferN[bufferN_size++] = number;
        }
        else {
            if ( bufferP_size == bufferP_cap){
                bufferP_cap *= 2;
                bufferP = (int*)realloc(bufferP, sizeof(int)*bufferP_cap);
            }
            bufferP[bufferP_size++] = number;
        }
    }

    printf("tab negative : ");
    for (int i = 0; i < bufferN_size; i++)
        printf("%d\n", bufferN[i]);

    printf("tab positive : ");
    for (int i = 0; i < bufferP_size; i++)
        printf("%d\n", bufferP[i]);

    free(bufferN);
    free(bufferP);
}

There are following problems in the code:

  1. malloc does not insert NULL at the end of allocated memory. So a check if(*bufferN == NULL) will not work. The pointer would dereference the memory and probably get a garbage value.
  2. The error rev_S3_ptr.c:14:16: error: comparison between pointer and integer [-Werror] if(*bufferN == NULL){ occur because you're comparing value (*bufferN) address against NULL (used for a nil address).
  3. The code rev_S3_ptr.c:19:4: error: value computed is not used [-Werror=unused-value] *bufferN++; throws an error because only an increment of address was needed. The deference does not help.
  4. The statement bufferP[i] means *(bufferP+i) hence the error while comparing against NULL.

Let's begin with the beginning:

int *bufferP = (int*)malloc(2*sizeof(int));
int *bufferN = (int*)malloc(2*sizeof(int));

This is correct, but you should not cast (don't use (int*)) the result of malloc(). Search "cast malloc result". And aside, why allocate 2 slots if you plan to make it grow as necessary? Why not 10 or 100? Why not only one?

Let's go ahead:

if(*bufferN == NULL){
  printf("No more place");
  exit(0);
}

Here, you should consider bufferN, not what is pointed to by it. NULL is used to check pointers themselves, not values pointed by pointers; this is why the compiler complains. Note anyway that bufferN will never change value by itself, automatically, so don't try to compare it in order to understand if the buffer is full. The only way to do it is to count how many items you put in.

Lastly:

        *bufferN= number;
        *bufferN++;

you correctly store the number in the location pointed by the pointer. May be ok. But in the next line you wanted to increment the pointer, but also you dereference it. It is not wrong, but unusual - in fact the compiler again complains.

The buffer works like a tab right?

Wrong. The buffer is a zone of memory, which is manipulated by you, perhaps using pointers, which in turn are manipulated by you. You must track what happens.

At the "No more place" I must double the size of the buffer and I don't know how to do this.

You use realloc() for this.

I don't want to do the entire job for you, but I can explain what you need. I will talk about a single buffer, the other is the same.

First, allocate a buffer like you are doing now, but for a single slot. And introduce a counter (an int) to count how many numbers are in the buffer. The counter is initially 0.

As the user enters a number, you store it like this:

bufferN[counterN] = number;
counterN++;

At this point, you know that the buffer is full. We started with a buffer with only one (and free) slot, now we have none... why not resize the buffer to add again a free slot? We know that we have counterN items in the buffer, that the buffer is full, so we want a new buffer with counterN+1 slots; realloc() can do what we need.

Note that to read and write in the buffer, the syntax bufferN[...] is easy and safe, because you always now (via counterN) how big the buffer is, and how many items it contains. And you don't touch the pointer itself.

There are other ways to do this, but this is one - not the cleanest, but reasonable. I hope this helps.

EDIT: after seeing another reply, I realized that the requirement is to double the size of the buffer. My suggestion above does not comply with this requirement. I am sorry... more work for you... we (you) must count not only the items that are added to the buffer, but also its size. Simply, another integer variable to manage. Well, there would be a trick to avoid this, but let's it alone :-)

Related