1

So just like in python list I wanted to try and implement using c (I am new to c programming). This is my code

// File name:- list.c

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

int main() 
{
    int myNumbers[] = {25, 50, 75, 100};
    // int length = len(myNumbers);
    push(myNumbers, 200, len(myNumbers));
    for(int i = 0; myNumbers[i]; i++){
        printf("array[%d] = %li\n", i, myNumbers[i]);
    };
    len(myNumbers);

    return 0;
}


// File name:- l.c

#include "l.h"
#include <stdio.h>

int len(int arr[])
{
    int i;
    for(i = 0; arr[i]!='\0'; i++){
        continue;
    };
    printf("Length is: %d\n", i);
    return i;
}

void push(int list[], int value, int length)
{
    // int length = len(list);
    list[length] = value;
}

The above code does give me the result I expect, i.e

Length is: 4
array[0] = 25
array[1] = 50
array[2] = 75
array[3] = 100
array[4] = 200
Length is: 5

Whereas when int myNumbers[] = {25, 50, 75, 100, 125}; or anything more than 4 values in the array...

The Result is given unexpected random values like:-

Length is: 5
array[0] = 25
array[1] = 50
array[2] = 75
array[3] = 100
array[4] = 125
array[5] = 200
array[6] = 2782528512
array[7] = 1952226512
array[8] = 1
Length is: 9

How to fix this issue? I had even tried by directly passing the length and even calling the function without passing the length, but none of them worked... I went through the code for any logic error, I wasn't able to find any..

I expect this as my result...

Length is: 5
array[0] = 25
array[1] = 50
array[2] = 75
array[3] = 100
array[4] = 125
array[5] = 200
Length is: 6
Meheer J
  • 43
  • 7
  • 1
    Your `len` is relying on the array to be terminated by zero. But it is not. Nevertheless, it is not a good assumption for *numerical* data. – Eugene Sh. Aug 04 '23 at 18:16
  • 1
    `myNumbers` is in the stack frame and its size/length is _fixed_--it can _not_ be increased. You probably want to redefine it as a pointer and use `malloc/realloc` to grow it dynamically. For an example of how to do this, see my answers: [Creation of Dynamic Array of Strings in C](https://stackoverflow.com/a/73737192/5382650) and [C Programming: Reading data from a file, dynamically allocating memory, placing contents in struct array](https://stackoverflow.com/a/66592519/5382650) – Craig Estey Aug 04 '23 at 18:23
  • @CraigEstey I'll look into these examples.. Thank you so much – Meheer J Aug 04 '23 at 18:31

4 Answers4

7

C does not automatically terminate arrays with zero (except for string literals). If you want a zero to mark the end of your array, you must put it there.

C does not automatically grow arrays. Your push routine will not make space in the array for a new element. It will corrupt your program.

To tinker with pushing numbers onto a list like that, you can declare myNumbers to have a lot of space, as with int myNumbers[100] = {25, 50, 75, 100, 0}; to reserve space for 100 elements and to mark the end of the first few with a zero. As you learn more about C, you will learn about other ways to manage memory.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • And even with string literals if a char array is not long enough, the null-terminator is not guaranteed to be there. E.g. `char str[5] = "hello";` – Chris Aug 04 '23 at 18:22
  • Hello Eric, we posted at the same time and we both chose an arbitrary length of 100 for example's sake... I like that. – chqrlie Aug 04 '23 at 18:24
  • 2
    The final `0` isn't strictly necessary, because all elements not explicitly initialised are set to `0`. – Weather Vane Aug 04 '23 at 18:24
  • Okay understood, so you are suggesting that i initialize the `myNumbers` with the length of 100. Just asking out of curiosity, if I during the runtime keep increasing the memory allocation without malloc... would it cause a lot of problem?? like `int myNumbers[100] = {25, 50, 75, 100, 0};` and -1 in the for loop for length and reinitialize 0 to my preferred number and add another 0 to it at the end?? – Meheer J Aug 04 '23 at 18:30
6

The array defined by int myNumbers[] = { 25, 50, 75, 100 }; has exactly 4 elements and does not have a null terminator. Hence calling len() or trying to push an element both have undefined behavior.

You could define myNumbers as int myNumbers[100] = { 25, 50, 75, 100 }; and your code would work up to 99 elements because the remaining elements will have been initialized to 0.

Note also that the printf format specifier %li expects a long int argument value, which myNumbers[i] is not. You should use %i or %d to output this int value as a decimal number.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Ohh okay... I understood, makes sense for the undefined behavior. Asking out of curiosity why does it work for 4 elements and not 4+ ?? – Meheer J Aug 04 '23 at 18:34
  • 1
    @MeheerJ: C arrays have a length fixed at the definition or allocation point and cannot be changed afterwards. Your definition specifies a length of 4 elements from the initializer. You cannot add more elements, accessing them as in `len()` or `push()` has undefined behavior and you observe that when you read elements beyond index 3 in your own code. Undefined behavior means anything can happen: random values, zero values, segmentation fault... anything. – chqrlie Aug 04 '23 at 19:21
1

The issue in your code is related to array bounds and memory access. When you declare an array in C like this: int myNumbers[] = {25, 50, 75, 100};, it has a fixed size of 4 elements. You cannot directly add elements to it beyond its initial size without causing undefined behavior, which is why you are getting unexpected random values.

To fix this issue, you need to handle dynamic memory allocation to increase the size of the array when you want to add more elements. Here's a modified version of your code to achieve this using dynamic memory allocation:

// File name: list.c

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

int main() 
{
    int* myNumbers = (int*)malloc(4 * sizeof(int)); // Allocate memory for 4 elements
    int length = 4;
    myNumbers[0] = 25;
    myNumbers[1] = 50;
    myNumbers[2] = 75;
    myNumbers[3] = 100;
    
    push(myNumbers, 125, &length);
    push(myNumbers, 200, &length);
    
    for (int i = 0; i < length; i++) {
        printf("array[%d] = %d\n", i, myNumbers[i]);
    }
    
    free(myNumbers); // Free the dynamically allocated memory
    
    return 0;
}

// File name: l.c

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

void push(int* list, int value, int* length)
{
    list[*length] = value;
    (*length)++;
}

// File name: l.h

#ifndef L_H
#define L_H

void push(int* list, int value, int* length);

#endif

In this version, the myNumbers array is allocated dynamically using malloc, and its size is initially set to 4. The length variable keeps track of the number of elements in the array. When you call the push function, it adds the new element to the end of the array and increments the length variable. This way, you can add elements beyond the initial size without any issue.

Remember to free the dynamically allocated memory using free(myNumbers) when you're done with the array to avoid memory leaks.

chamanswami
  • 37
  • 1
  • 3
  • Understood this clearly. I have a small doubt, so now u initialized this with a starting of 16 bytes (4*4), now when i add more elements... what about the extra required space?? – Meheer J Aug 04 '23 at 18:57
  • You have not mentioned or used `realloc()` anywhere. It should be in the `push()` function. And `push()` should `return` the new base value (or modify a `int **list` argument). – Weather Vane Aug 04 '23 at 18:57
0

you can declare int myNumbers[] with more space like -

int myNumbers[100] = {25, 50, 75, 100, 125};