-1

The program is long so I can't really post everything so I'm giving the abridged version that will hopefully be relevant to others too.

Right now the program uses this data structure in main:

char b[100];
gets(b);
char arr[5][100]; 
sscanf(b, "%s", arr[0]); //user enters a query in the command line
//initializes statement based on what arr[0] is 
//in this case, calls myFunction 

I want to use malloc to make the char array of unknown size now instead of what I have now. There are some examples online on how to make a 2D array using malloc but I don’t know if the type of implementation I use will mess up with my already made function that follows this structure:

void myFunction(char *b, char *argv[]) {
    char arr[5][100];
    sscanf(b, "%s %s", arr[0], arr[1]);
    //do stuff to the array like strcpy(arr[0],argv[1]);
    // or FILE *f = fopen(arr[0], "r");
}

Would I just initialize malloc in main and do the same in the function as well? I feel like if I do that, playing around with the array in the function will no longer be as simple as I’ve already done it since I'm dealing with dynamic memory now.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Sam
  • 11
  • 1
  • 1
    There are no "2D arrays of unknown size". A 2D array **always** has a known size. Otherwise indexing would be impossible and the code could not iterate all elements in both dimensions. – too honest for this site Jul 30 '17 at 20:52
  • @Olaf I knew I might get flagged for that. I just had no idea how to word the question better but I updated it. Hopefully it is less misleading. Thanks! – Sam Jul 30 '17 at 20:59
  • 5
    [Start by forgetting that `gets()` was ever a part of the C language](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used); it isn't any longer (as of C11). Then, create a [MCVE] that more clearly explains your question. Are you concerned about passing the dynamic array to a function? In the posted code, there are two different `arr`s, in two different scopes; is this intentional? – ad absurdum Jul 30 '17 at 21:00
  • 1
    [You may want to read about dynamically allocating 2d arrays here](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – ad absurdum Jul 30 '17 at 21:03
  • 1
    You cannot `switch` based on an array – M.M Jul 30 '17 at 21:08
  • it's unclear what your `sscanf` statement is supposed to be doing, you have one `%` in the format string but two arguments following. And are you intending to pass the array from main to the function at any point? – M.M Jul 30 '17 at 21:09
  • @Sam: I did not flag the question (for what reason would it be flagged??)! – too honest for this site Jul 30 '17 at 21:19
  • It is hard to help when you say things like "uses" (how?) & "make the char array of unknown size" (how?) instead of giving properties of representations and assumptions manipulations make (even if you don't know all of what will be necessary). An answer becomes a chapter re dynamic/ragged/pointer implementation of arrays--read some. Keep clear the many uses of "array" here--conceptual thing you want to represent, various C nested types/objects sometimes part of others, data structure using pointers. PS Examples abridged from your actual code should run & exhibit the problem, per [mcve]. – philipxy Jul 30 '17 at 21:53

2 Answers2

1

Here is how you can allocate an array of arrays (aka 2D array) and store its address to a pointer with the appropriate type:

void myFunction(char *b, char *argv[]) {
    char (*arr)[100] = malloc(sizeof(*arr) * 5);
    sscanf(b, "%99s%99s", arr[0], arr[1]);
    //do stuff to the array like strcpy(arr[0], argv[1]);
    // or FILE *f = fopen(arr[0], "r");
}

Also do not use gets().

chqrlie
  • 131,814
  • 10
  • 121
  • 189
-1

As Olaf stated in his comment, arrays have a known size. So by using this size, you could allocate memory in a "2D"-way by doing something as follows:

  • Assuming you want to allocate an [5][100] array: nrows = 5, ncols = 100:

    char *array = malloc(sizeof(char) * nrows * ncols);
    

Now that you have your reserved space in the heap for your 2D array, you only need to build a formula in which you can access every "cell" of your array.

When nrows = 0 then you are in the first row of your so-called 2D array and when nrows = 4 then you are in the last row. Since you are allocating sizeof(char) * nrows * ncols bytes, the indexes for nrows and ncols only go until nrows - 1 and ncols - 1.

With that in mind you can access any cell of your array via

char *get_value(char *array, int row, int col) {
    return (array + row * ncols + col);
}
CRoemheld
  • 889
  • 7
  • 26
  • sizeof(char) == 1, always, and is hence redundant. – Bjorn A. Jul 30 '17 at 21:06
  • This is not guaranteed to work for anything other than character types I guess... – Antti Haapala -- Слава Україні Jul 30 '17 at 21:08
  • the formula applies for every array which holds one specific type. thats whats pointer arithmetics is. – CRoemheld Jul 30 '17 at 21:12
  • @BjornA. I merely used `sizeof(char)` for this specific example. You are correct; a char is 1 byte in size, but if you want to change the type of array in, lets say an integer array, you simply change `char` to `int` and the formula still applies. – CRoemheld Jul 30 '17 at 21:16
  • It cannot be assumed that x=5, y=100. I asked this question because I want to use malloc to allocate an unknown size because it can vary. – Sam Jul 30 '17 at 21:16
  • @Sam you can set the values of `x` and `y` to whatever value you like. The heap grows and shrinks dynamically while the program is running, you you can use your user input from `sscanf` or whatever I/O function you would use and set the value from `x` and `y` to whatever you typed in. – CRoemheld Jul 30 '17 at 21:18
  • 2
    Better to use `char *array = malloc(sizeof *array * x * y);`. Avoiding the explicit type in the `sizeof` operand means that there is only one place to modify when types change. – ad absurdum Jul 30 '17 at 21:18
  • @DavidBowling If you mean `sizeof(*array) * x * y then maybe yes, I never used it that way since i always knew beforehand what type I would use to store data. – CRoemheld Jul 30 '17 at 21:20
  • That's not what I wrote. This is not a 2D array and the manual indexing is very error-prone. The correct way would be to use a 2D array. – too honest for this site Jul 30 '17 at 21:21
  • 1
    Remember that `sizeof` is an operator, not a function. The parentheses are only needed when the operand is a type, but not when the operand is an expression. Some do prefer the parentheses, though. – ad absurdum Jul 30 '17 at 21:22
  • @Olaf not much more error-proning than any regular 2D array. Once the formular is set, the code yould work fine. Of course you can add checks for your parameters to be sure the indexes aren't out of bounds. – CRoemheld Jul 30 '17 at 21:24
  • @DavidBowling you're right. Even I can profit from this topic as it seems. ;) – CRoemheld Jul 30 '17 at 21:25
  • 1
    @CRoemheld: You have to use the expression for every access. The index-operator uses the multiplication with the length of the innter array implicitly. It is definitively less error prone if the compiler knows more about what you do and you don't have redundant code. It also is better readable. Finally: what is your obj3ection **against** using a 2D array? – too honest for this site Jul 30 '17 at 21:28
  • @Olaf I never said I have a reason against using a regular 2D array. I (in my understanding) gave **Sam** a possible solution for creating an 2D array via malloc. To use this, you need a formula to access any cell of your new array. With a regular 2D array, you would write `char c = array[x][y]`, and with the malloc solution you would write `char c = *(get_value(array, xi, yi))` which is basically the same as `array[xi][yi]`. My own opinions are a completely other matter ;) – CRoemheld Jul 30 '17 at 21:32
  • @CRoemheld: Again: that is not a 2D array. There is no problem allocation a 2D array with `malloc` either. Maybe you need to read about VLAs? – too honest for this site Jul 30 '17 at 21:34
  • @Olaf I looked at my code again, are you maybe reffering to the fact that you want to access the VLA using array[x][y] instead of my function? I realized there's a mistake, the variable `array` at the allocation via malloc should be a pointer to pointer, not a single pointer. – CRoemheld Jul 30 '17 at 21:41
  • 1
    @CRoemheld: There is no VLA in your code, nor can you use the double index-operator for a pointer to `int`! That would invoke undefined behaviour for violating the effective type rule (the compiler should warn). Please read the standard and make sure you are correct before posting such answers. – too honest for this site Jul 30 '17 at 21:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150547/discussion-between-croemheld-and-olaf). – CRoemheld Jul 30 '17 at 21:53
  • There is nothing inherently wrong with indexing into a 1d array this way; but it is a 1d array, not a 2d array. Maybe better to call it a simulated 2d array. Also, it may be clearer to use, e.g., `nrows` and `ncols`, instead of `x` and `y`, especially in the indexing calculation. Using `x` for the number of rows and `xi` for the row index seems unintuitive. – ad absurdum Jul 30 '17 at 22:13
  • @DavidBowling Yes thats right. Maybe I should have renamed my array that way. I initially thought we are looking for a 2D array completely allocated via malloc. But since it is just a 1D array "masked" as a 2D array (the functionalities and use would be the same using the `get_value` function) it might not exactly be what Sam was looking for. – CRoemheld Jul 30 '17 at 22:17