How to reassign a array in c? - c

#include <stdio.h>
#include <stdlib.h>
void reasi(char** a){
char* x[] = {"1","22","333"};
a = x;
}
int main(){
char* a[] = {"bob","alice","tom"};
reasi(a);
for(int i=0; i< 3; i++){
printf("%s\n",a[i]);
}
}
The desired output should be {"1","22","333"}, but it won't work if I assign the value like that. I do know how to change the value of an int or char but don't know how to reassign the value to an array (without dynamically allocating memory). I tried to update each element inside "a" and it works. Thank you.

What you're doing won't work. You're simply creating a local array and then assigning your local parameter a to the beginning of this array (which changes nothing about the a in main). So the real thing isn't modified.
To actually modify this, you can either do a plain for loop:
// NOTE: this assumes array has the same number of elements as x
void reasi(char** a)
{
char* x[] = {"1","22","333"};
for (unsigned i = 0; i < sizeof x / sizeof *x; ++i)
a[i] = x[i];
}
Or use memcpy:
#include <string.h>
// NOTE: this assumes array has the same number of elements as x
void reasi(char** a)
{
char* x[] = {"1","22","333"};
memcpy(a, x, sizeof x);
}

Your array is not a 2D array. By seeing your code I assume you mistaken 1D array for 2D array, hence I will answer according to it
#include <stdio.h>
#include <stdlib.h>
void reasi(char** a){
a[0] = "1";
a[1] = "22";
a[2] = "333";
}
int main()
{
char* a[] = {"bob","alice","tom"};
reasi(a);
for(int i=0; i< 3; i++)
{
printf("%s\n",a[i]);
}
}
This will give you your desired output.

In C an array has a fixed size. You cannot resize it after the fact. If the size always stays the same, you can copy the new array:
#include <stdio.h>
#include <string.h>
void reasi(char const **a) {
char const *x[] = {"1", "22", "333"};
memcpy(a, x, sizeof x);
}
int main() {
char const *a[] = {"bob", "alice", "tom"};
reasi(a);
for (int i = 0; i < 3; i++)
puts(a[i]);
}
If you do want to resize the array, you are going to have to allocate it dynamically with malloc.

Both a and x are each an array of pointers to char. In C, you cannot assign the contents of an array C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) "the array object ... is not an lvalue."
Instead, you must assign each element (pointer) from x to a or use memcpy() to accomplish the same.
Further, hardcoding the contents of x in your function makes little sense. Why? You have just written a function that does nothing but assign the pointers (to String-Literals "1", "22", "333") and is incapable of doing anything else -- useful.
Why not declare x in main() and pass it as a parameter along with a and the number of elements? That way, you can pass any array of pointers to char as x (with at least 3 elements) and reassign the elements to a).
For example:
#include <stdio.h>
void reasi (char **a, char **x, size_t nelem)
{
for (size_t i = 0; i < nelem; i++) {
a[i] = x[i];
}
}
int main() {
char *a[] = {"bob","alice","tom"},
*x[] = {"1","22","333"},
*y[] = {"4","55","666","7777","8888"};
size_t n = sizeof a / sizeof *a;
reasi (a, x, n);
puts ("x->a");
for (size_t i = 0; i < n; i++) {
printf ("%s\n", a[i]);
}
reasi (a, y, n);
puts ("\ny->a");
for (size_t i = 0; i < n; i++) {
printf ("%s\n", a[i]);
}
reasi (a, y + 2, n);
puts ("\ny+2->a");
for (size_t i = 0; i < n; i++) {
printf ("%s\n", a[i]);
}
}
The refactoring above generalizes your reasi() function, making it reusable and a bit more useful than a single use case of "1", "22", "333".
Example Use/Output
Running you get the expected:
$ ./bin/reasi
x->a
1
22
333
y->a
4
55
666
y+2->a
666
7777
8888
Wrapping memcpy() in a function in that case wouldn't buy you any benefit, you could simply call memcpy (a, x, n * sizeof *a); from main() and avoid the function call overhead (which a decent compiler would likely optimize out anyway).
Look things over and let me know if you have further questions.

Related

C: how to give 2D Array to a function

I want to pass a 2D array already filled with chars to a different method to do something with it.
Background: I am trying to implement GameOfLife. And I have already successfully implement the gameboard with a random amount of living cells. But now I want to pass the board(Array) to a different method to continue working with it. How to do so?
//wow das wird hurenshon
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void spielStarten(int x, int amountOfLiving){
char feld[x][x];
for(int i = 0; i < x; i++){
for(int j = 0; j < x; j++){
feld[i][j] = 'o';
}
}
for(int i = 0; i < amountOfLiving; i++){
int a = (rand()%x);
int b = (rand()%x);
feld[a][b] = 'x';
}
printf("Gameboard: \n");
for(int i = 0; i < x; i++){
for(int j = 0; j < x; j++){
printf("%c ", feld[i][j]);
}
printf("\n");
}
spielRun(feld);
}
void spielRun(char feld[][]){
int neighbCount;
char feldNew[][] = feld[][];
for(int i = 0; i < x; i++) {
for(int j = 0; j < x; j++) {
checkForNeighbours(feld[x][y]);
// in progress
}
}
}
int main(int argc, char* argv[]){
srand(time(NULL));
int x = 16;
if(argc < 2 || argc > 3){
printf("2. Argument eine Zahl fuer Feldgroesse eingeben\n");
printf("1. Argument eine Zahl 0-10 fuer ungefähre prozentuale Belegung mit lebenden
Zellen eingeben \n");
return 0;
}
if(argv[2] != NULL){
x = atoi(argv[2]);
}
int i;
i = atoi(argv[1]);
i = (x^2)*(0,1*i);
spielStarten (x,i);
return 0;
}
In the last line of the Method "Spiel starten" i want to give the array to the next Method "spielRun".
Edit: thanks to an other user I found this struture:
void printarray( char (*array)[50], int SIZE )
But it doesn't work for me since I can´t hardcode the number, because the arraysize depends on a user input.
thanks!
The difficulty here is that the size of your array is not known statically (once upon a time, your code would even not compile for the same reason).
That, combined with the fact that 2D-arrays are not arrays of 1D arrays (contrarily to what happen when you malloc a int ** and then every int * in it), and so it doesn't make sense not to specify the size when passing it to a function.
When using arrays of arrays (technically, pointers to a bunch of pointers to ints), like this
void f(int **a){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int **t=malloc(10*sizeof(int *));
for(int i=0; i<10; i++) t[i]=malloc(20*sizeof(int));
f(t);
}
That code is useless, it prints only unitialized values. But point is, f understands what values it is supposed to print. Pointers arithmetics tells it what a[1] is, and then what a[1][0] is.
But if this 2D-array is not pointers to pointers, but real arrays, like this
void f(int a[][20]){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int t[10][20];
f(t);
}
Then, it is essential that the called function knows the size (or at least all sizes, but for the first dimension) of the array. Because it is not pointers to pointers. It is an area of 200 ints. The compiler needs to know the shape to deduce that t[5][3] is the 5×20+3=103th int at address t.
So, that is roughly what is (better) explained in the link that was given in comments: you need to specify the size.
Like I did here.
Now, in your case, it is more complicated, because you don't know (statically) the size.
So three methods. You could switch to pointers to pointers. You could cast your array into a char * and then do the index computation yourself (x*i+j). Or with modern enough C, you can just pass the size, and then use it, even in parameters, declaration
void f(int x, int a[][x]){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int t[10][20];
f(t);
}
Anyway, from an applicative point of view (or just to avoid segfault) you need to know the size. So you would have had to pass it. So why not pass it as first parameter (Note that the function in which you have this size problem, spielRun, does refers to a x, which it doesn't know. So, passing the size x would have been your next problem anyway)
So, spielRun could look like this (not commenting in other errors it contains)
void spielRun(int x, char feld[][x]){
int neighbCount;
char feldNew[][] = feld[][]; // Other error
for(int i = 0; i < x; i++) {
for(int j = 0; j < x; j++) {
checkForNeighbours(feld[i][j]); // Corrected one here
// in progress
}
}
}
And then calls to this spielRun could be
spielRun(x, feld);
Note that I address only the passing of array of size x here. There are plenty of other errors, and, anyway, it is obviously not a finished code. For example, you can't neither declare a double array char newFeld[][] = oldFeld[][]; nor affect it that way. You need to explicitly copy that yourself, and to specify size (which you can do, if you pass it).
I am also pretty sure that i = (x^2)*(0,1*i); does not remotely what you expect it to do.

GCC Compilation Error on array assignment

I am trying to convert a string into its equivalent matrix form in C. The matrix would have 3 rows and as many columns as required. The following code doesn't compile, and I haven't figured out what's going wrong.
The error that GCC throws is:
app.c:10:25: error: subscripted value is not an array, pointer, or vector
printf("%d\n", arr[i][k]);
~~~^~
1 error generated.
Main file (app.c):
#include <stdio.h>
#include "converter.h"
int main() {
char source[] = "This is the source. "; // placeholder text
int arr = convert(source);
for (int i = 0; i < 21; i++) {
for (int k = 0; k < 3; k++) {
printf("%d\n", arr[i][k]); // error occurs at this line.
}
}
return 0;
}
converter.c file:
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include "converter.h"
// Converts the entire string into an multi-dimensional array.
int convert(char text[]){
// copy the input text into a local store.
char store[strlen(text)];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = strlen(store)%3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
// covert the source into an array
int arr[3][strlen(store)/3];
int steps = strlen(store)/3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return arr;
}
converter.h file:
int convert(char text[]);
There are multiple issues in this code.
The allocating storage for string, one must include one byte for a null terminator. Replace:
char store[strlen(text)];
with:
char store[strlen(text) + 1];
Additionally store must be big enough to contain the excess which is up to 3 spaces.
char store[strlen(text) + 3 + 1];
In C you cannot use an array as a value. It is converted to a pointer to it's first element in pretty must every context. Therefore it is not possible to return an array directly. It could be workaround by wrapping an array with a struct but it a topic for another day.
As result return arr will be equivalent to return &arr[0] which is int (*)[XXX] a pointer to int array of size XXX.
Never ever return a pointer to an object with automatic storage. It's Undefined Behaviour. I know that the intention was returning an array not a pointer to it. Create an object with dynamic storage with malloc-like function to safely return a pointer.
Returning Variable Length Array (VLA) by value is not possible because Variably Modified (VM) types cannot be defined at file scope.
It looks that indices are swapped in:
printf("%d\n", arr[i][k]);
I guess it should be arr[k][i].
Now... let's solve it.
Returning VLA is tricky. One solution is to pass a pointer to VLA as an argument. See https://stackoverflow.com/a/14088851/4989451.
The issue with this solution is that the caller must be able to compute the dimensions.
The other way it to wrap the result of the convert() to a struct. Note that the function and the struct can share the name. The result with have the sizes of VLA as n and m members and the pointer to the data as arr. The caller need to cast it to proper VM type.
To cumbersome casts between the non-trivial pointer types, one can cast via void*.
When all work with the array is done, release it memory with free().
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Converts the entire string into an multi-dimensional array.
struct convert {
int n, m;
int *arr;
} convert(char text[]){
// copy the input text into a local store.
size_t textlen = strlen(text);
char store[textlen + 3 + 1];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = textlen % 3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
size_t storelen = strlen(store);
// allocate VLA with dynamic storage
int (*arr)[storelen / 3] = malloc(3 * sizeof *arr);
// covert the source into an array
int steps = storelen / 3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return (struct convert){ .n = 3, .m = steps, .arr = (int*)arr };
}
int main() {
char source[] = "This is the source. "; // placeholder text
struct convert res = convert(source);
int n = res.n, m = res.m;
int (*arr)[m] = (void*)res.arr;
for (int i = 0; i < n; i++, puts("")) {
for (int k = 0; k < m; k++) {
printf("%d ", arr[i][k]); // error occurs at this line.
}
}
free(arr);
return 0;
}

Declaring and copying an array of char strings in c

I made a c program that attempts to add the values of one string array to another using a separate method:
#include <stdio.h>
#include <stdlib.h>
void charConv(char *example[])
{
example= (char* )malloc(sizeof(char[4])*6);
char *y[] = {"cat", "dog", "ate", "RIP", "CSS", "sun"};
printf("flag\n");
int i;
i=0;
for(i=0; i<6; i++){
strcpy(example[i], y[i]);
}
}
int main() {
char *x[6];
charConv( *x[6]);
printf("%s\n", x[0]);
}
However it keeps returning a segmentation fault. I'm only beginning to learn how to use malloc and c in general and its been puzzeling me to find a solution.
To pin-point your problem: you send *x[6] (here - charConv( *x[6]);) which is the first char of the 7'th (!!!) string (Remember, C is Zero-Base-Indexed) inside an array of 6 string you didn't malloc -> using memory you don't own -> UB.
Another thing I should note is char[] vs char * []. Using the former, you can strcpy into it strings. It would look like this:
'c' | 'a' | 't' | '\0' | 'd' | 'o' | 'g' | ... [each cell here is a `char`]
The latter ( what you used ) is not a contiguous block of chars but a array of char *, hence what you should have done is to allocate memory for each pointer inside your array and copy into it. That would look like:
0x100 | 0x200 | 0x300... [each cell is address you should malloc and then you would copy string into]
But, you also have several problems in your code. Below is a fixed version with explanations:
#include <stdio.h>
#include <stdlib.h>
void charConv(char *example[])
{
// example= (char* )malloc(sizeof(char[4])*6); // remove this! you don't want to reallocate example! When entering this function, example points to address A but after this, it will point to address B (could be NULL), thus, accessing it from main (the function caller) would be UB ( bad )
for (int i = 0; i < 6; i++)
{
example[i] = malloc(4); // instead, malloc each string inside the array of string. This can be done from main, or from here, whatever you prefer
}
char *y[] = {"cat", "dog", "ate", "RIP", "CSS", "sun"};
printf("flag\n");
/* remove this - move it inside the for loop
int i;
i=0;
*/
for(int i=0; i<6; i++){
printf("%s\t", y[i]); // simple debug check - remove it
strcpy(example[i], y[i]);
printf("%s\n", example[i]); // simple debug check - remove it
}
}
int main() {
char *x[6];
charConv( x); // pass x, not *x[6] !!
for (int i = 0; i < 6; i++)
{
printf("%s\n", x[i]); // simple debug check - remove it
}
}
As #MichaelWalz mentioned, using hard-coded values is not a good practice. I left them here since it's a small snippet and I think they are obvious. Still, try to avoid them
You need to start by understanding the pointers and some other topics as well like how to pass an array of strings to a function in C etc.
In your program, you are passing *x[6] in charConv() which is a character.
Made corrections in your program -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void charConv(char *example[], int num)
{
int i;
for (i = 0; i < num; i++){
example[i] = (char* )malloc(sizeof(char)*4);
}
const char *y[] = {"cat", "dog", "ate", "RIP", "CSS", "sun"};
for(i = 0; i < num; i++){
strcpy(example[i], y[i]);
}
}
int main() {
char *x[6];
int i = 0;
charConv(x, 6);
/* Print the values of string array x*/
for(i = 0; i < 6; i++){
printf("%s\n", x[i]);
}
return 0;
}

Using 3d array outside a function

I have a function in which I make a 3D array and fill in all the values. I also have to pass a pointer to the function which will assign the memory location of the 3D array to that function so that it can be used outside of that function. Currently, I am doing something which does not seem to work, can someone guide me to the best possible resolution?
int (*arr)[4];
void assign_3D(int (*arr)[4])
{
int local[2][3][4]; //probably we should pass *local?
memset(local, 0, sizeof(int)*2*3*4); // fill the local array with numbers
arr = local;
}
printf("%d\n", arr[1][2][3]);
I know I have written horrible code above. But I am learning :).
It is not possible to assign arrays. You are also using the wrong type for the argument (int (*)[5] is not what a int [2][3][4] decays into, use int (*)[3][4] as the argument type). Once you have the correct type, you can use memcpy() to do the assignment:
#include <string.h>
#include <stdio.h>
int arr[2][3][4];
void assign_3D(int (*arr)[3][4]) {
int local[2][3][4];
memset(local, 0, sizeof(local)); //pass local here, because it is not a pointer but an array. Passing *local would only initialize the first element of the array, i. e. the first 2D slice of it.
// fill the local array with numbers
memcpy(arr, local, sizeof(local));
}
int main() {
assign_3D(arr);
printf("%d\n", arr[1][2][3]);
}
But you can also return a newly allocated array from your function:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef int arrayType[2][3][4];
arrayType* create_3D() {
arrayType* result = malloc(sizeof(*result)); //here we need to dereference because result is a pointer and we want memory for the array, not the pointer.
memset(result, 0, sizeof(*result));
(*result)[1][2][3] = 7; // fill the local array with numbers
return result; //that's easy now, isn't it?
}
int main() {
arrayType* array = create_3D();
printf("%d\n", (*array)[1][2][3]);
free(array); //cleanup
}
Edit:
You mention that the size of the first dimension is not know before the function is run. In that case, you have to use the malloc() approach, but a bit differently:
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef int sliceType[3][4];
sliceType* create_3D(size_t* firstDimSize) {
*firstDimSize = 2;
size_t arraySize = *firstDimSize*sizeof(sliceType);
sliceType* result = malloc(arraySize);
memset(result, 0, arraySize);
result[1][2][3] = 7; // fill the local array with numbers
return result;
}
int main() {
size_t firstDim;
sliceType* array = create_3D(&firstDim);
printf("%d\n", array[1][2][3]);
free(array); //cleanup
}
There are two different ways to allocate a 3D array. You can allocate it either as a 1D array of pointers to a (1D array of pointers to a 1D array). This can be done as follows:
int dim1, dim2, dim3;
int i,j,k;
int *** array = (int ***)malloc(dim1*sizeof(int**));
for (i = 0; i< dim1; i++) {
array[i] = (int **) malloc(dim2*sizeof(int *));
for (j = 0; j < dim2; j++) {
array[i][j] = (int *)malloc(dim3*sizeof(int));
}
}
Sometimes it is more appropriate to allocate the array as a contiguous chunk. You'll find that many existing libraries might require the array to exist in allocated memory. The disadvantage of this is that if your array is very very big you might not have such a large contiguous chunk available in memory.
const int dim1, dim2, dim3; /* Global variables, dimension*/
#define ARR(i,j,k) (array[dim2*dim3*i + dim3*j + k])
int * array = (int *)malloc(dim1*dim2*dim3*sizeof(int));
To access your array you just use the macro:
ARR(1,0,3) = 4;

Creating an array of int arrays in C?

Let us say I have the following method prototype:
void mix_audio(int *vocal_data_array, int *instrumental_data_array, int *mixed_audio_array, FOURTH ARGUMENT)
{
}
How would I:
Initialize an array_of_arrays before the above argument so as to pass it as the fourth argument?
In the method, make it so that the first value of my array_of_arrays is the array called vocal_data, that the second value of my array is instrumental_data_array and the third value is mixed_audio_array.
How would I later then loop through all the values of the first array within the array_of_arrays.
I hope I'm not asking too much here. I just thought it would be simple syntax that someone could spit out pretty quickly :)
Thanks!
EDIT 1
Please note that although I've showed by my example an array_of_arrays of length 3 I'm actually looking to create something that could contain a variable length of arrays.
Simple array of arrays and a function showing how to pass it. I just added fake values to the arrays to show that something was passed to the function and that I could print it back out. The size of the array, 3, is just arbitrary and can be changed to whatever sizing you want. Each array can be of a different size (known as a jagged array). It shows your three criteria:
Initialization, Assigning values to each index of arrayOfArrays, The function demonstrates how to extract the data from the array of arrays
#include <stdio.h>
void mix_audio(int *arr[3]);
int main() {
int *arrayOfArrays[3];
int vocal[3] = {1,2,3};
int instrumental[3] = {4,5,6};
int mixed_audio[3] = {7,8,9};
arrayOfArrays[0] = vocal;
arrayOfArrays[1] = instrumental;
arrayOfArrays[2] = mixed_audio;
mix_audio(arrayOfArrays);
return(0);
}
void mix_audio(int *arr[3]) {
int i;
int *vocal = arr[0];
int *instrumental = arr[1];
int *mixed_audio = arr[2];
for (i=0; i<3; i++) {
printf("vocal = %d\n", vocal[i]);
}
for (i=0; i<3; i++) {
printf("instrumental = %d\n", instrumental[i]);
}
for (i=0; i<3; i++) {
printf("mixed_audio = %d\n", mixed_audio[i]);
}
}
From your question it sounds like you actually want a struct containing your arrays, something like:
struct AudioData {
int* vocal_data_array;
unsigned int vocal_data_length;
int* instrumental_data_array;
unsigned int instrumental_data_length;
int* mixed_audio_array;
unsigned int mixed_audio_length;
};
For the array allocation using the example of an array of integers:
int** x = malloc (sizeof (int*) * rows);
if (! x) {
// Error
}
for (int i = 0; i < rows; ++i) {
x[i] = malloc (sizeof (int) * columns);
if (! x[i]) {
// Error
}
}

Resources