Manipulate variable length two dimensional array through a function - c

I am trying to write data into a variable length two dimensional array and my program keeps seg-faulting when I call myfunc but it works fine when I try to perform the same manipulation outside of a function. I can tell that the issues is that the address pointed to at array[0] doesn't equal the address pointed to at data[0]. Can someone advise me as to the root cause of this issue and proper way to rewrite myfun.
void myfun(unsigned char **array){
printf("array = %p, array[0] = %p\n", array, array[0]);
//This line below causes a segfault
strcpy(array[0], "Position0");
}
int main(void) {
int row = rand() % 5 + 1; // random number between 1-5
int col = rand() % 10 + 20; // random number between 20-29
unsigned char data[row][col];
printf("data = %p, data[0] = %p\n", data, data[0]);
//This function call causes a segfault
myfun(data);
printf("%s\n", data[0]);
//This works
strcpy(data[1], "Position1");
printf("%s\n", data[1]);
return 0;
}

Since you are clearly using C99 or later and a compiler with VLA (variable length array) support, you can write the function correctly quite easily:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void myfun(int rows, int cols, char array[rows][cols])
{
printf("array = %p, array[0] = %p\n", array, array[0]);
strcpy(array[0], "Position0");
printf("a[0] = [%s]\n", array[0]);
}
int main(void)
{
int row = rand() % 5 + 1; // random number between 1-5
int col = rand() % 10 + 20; // random number between 20-29
unsigned char data[row][col];
printf("data = %p, data[0] = %p\n", data, data[0]);
myfun(row, col, data);
printf("%s\n", data[0]);
strcpy(data[1], "Position1");
printf("%s\n", data[1]);
return 0;
}

The problem is the function definition. If you want to pass a matrix the way you did, you have to allocate it dynamically, but that's another story. I'll explain the error.
The C language actually implement the static matrices as a single array of size row*col. That is for efficiency.
When you pass the static matrix to that function, you got a problem: it expects a double pointer, but what you pass is actually a single pointer requiring the number of columns. You have to write like this:
void myfun(unsigned char array[][col]){ ...
That's how you should define it, where col is the number of columns.
The problem's that you don't know the number of columns, it's variable, so I suggest you use malloc or calloc to alocate a dynamic matrix.
Editing: look at this link posted as comment by n.m. for details on the static matrix that C implements: Is 2d array a double pointer?

Related

How to reassign a array in 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.

Having trouble with memory leak

I am trying to generate a Fibonacci sequence by allocating space for 2 elements, so I need my array a[0] and a[1] to be constantly updated until it outputs 89 as the final number.
This is my code:
#include <stdio.h>
#include <stdlib.h>
void fib2(int* a);
int main()
{
int *pointer;
//allocates space for 2 elements for pointer
pointer = (int*)malloc(2 * sizeof(int*));
//prints first two fibonacci values
printf("0 1 ");
//calls fib2 func and apsses pointer into it
fib2(pointer);
//frees pointer memory
free(pointer);
printf("\n");
return 0;
}
//generates fibonacci sequence
void fib2(int* a)
{
int i;
//allocates space for 2 elements
a = (int*)malloc(2 * sizeof(int*));
//initial fibonacci array initialized
a[0] = 0;
a[1] = 1;
//generates and calculates fibonacci sequence and prints
for(i = 2; i < 12; i++)
{
a[i] = a[i - 1] + a[i - 2];
printf("%d ", a[i]);
}
}
I tried freeing of a[] by doing free(a); but it outputs to the console like this
**edit this is the valgrind output
There are a number of problems.
Problem 1 Wrong malloc
int *pointer;
//allocates space for 2 elements for pointer
pointer = (int*)malloc(2 * sizeof(int*));
^^^^^^^^^^^^
The sizeof should be sizeof(int) as you want to allocate space for a number (2) int. Besides that you don't need the cast. A better way to write this is:
pointer = malloc(2 * sizeof *pointer);
Problem 2 You never use pointer for any thing
You do pass its value to fib2 so that its value goes into variable a. However, immediately after you do:
a = (int*)malloc(2 * sizeof(int*)); // also sizeof wrong again
so you actually overwrite whatever value that passed. Your call of fib2 could just as well be:
fib2(NULL);
In other words: Don't do malloc both in main and in fib2. Select one place.
Problem 3 The memory in malloc'ed in fib2 are never free'ed
Your current code leaks memory because fib2 doesn't end with code like: free(a);
Problem 4 You allocate too little memory
Obviously you want 12 elements in the integer array but you only allocate ! Change code to be:
a = malloc(12 * sizeof *a);
Putting things together it could look:
#include <stdio.h>
#include <stdlib.h>
void fib2(int* a, int n);
#define NUMBERS_TO_CALCULATE 12
int main()
{
int *pointer;
//allocates space for NUMBERS_TO_CALCULATE elements for pointer
pointer = malloc(NUMBERS_TO_CALCULATE * sizeof *pointer);
if (pointer == NULL) exit(1);
//calls fib2 func and apsses pointer into it
fib2(pointer, NUMBERS_TO_CALCULATE);
// ... use pointer for other things ...
//frees pointer memory
free(pointer);
return 0;
}
//generates fibonacci sequence
void fib2(int* a, int n)
{
int i;
if (n < 2) return;
//initial fibonacci array initialized
a[0] = 0;
a[1] = 1;
//prints first two fibonacci values
printf("0 1 ");
//generates and calculates fibonacci sequence and prints
for(i = 2; i < n; i++)
{
a[i] = a[i - 1] + a[i - 2];
printf("%d ", a[i]);
}
printf("\n");
}
Note: If you don't want to use pointer for other things in main, I'll suggest that you move the malloc and free into fib2
Edit based on comments from OP
In comments OP tells about a number of restriction like:
Must use malloc
Only allowed to malloc 2 integers (I assume this also means that local variables are not allowed in fib2)
Function prototype must be void fib2(int* a)
Must print values less or equal 89
With those restrictions the program could look:
#include <stdio.h>
#include <stdlib.h>
void fib2(int* a);
int main()
{
int *pointer;
//allocates space for 2 integer elements for pointer
pointer = malloc(2 * sizeof *pointer);
if (pointer == NULL) exit(1);
//initialize fibonacci start values
pointer[0] = 0;
pointer[1] = 1;
//calls fib2 func and apsses pointer into it
fib2(pointer);
//frees pointer memory
free(pointer);
return 0;
}
//generates fibonacci sequence
void fib2(int* a)
{
//prints first two fibonacci values
printf("%d %d ", a[0], a[1]);
//generates and calculates fibonacci sequence and prints
while(a[1] < 89)
{
a[1] = a[1] + a[0]; // Calculate next number and save in a[1]
printf("%d ", a[1]); // Print it
a[0] = a[1] - a[0]; // Calculate the number for a[0]
}
printf("\n");
}

Why I cannot use int arr[2][2] as a parameter?

void setArr(int x[2][2], int a, int b)
{
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
x[i][j] = 0;
}
int main(void)
{
int *arr[2];
for (int i = 0; i < 2; i++) {
arr[i] = malloc(sizeof(int) * 2);
}
setArr(arr, 2, 2);
}
I know this code will not work, but I do not know the reason behind it. Can any one explain to my why, in this case, I cannot use x[2][2] as a parameter to receive arr.
Thanks
I put the code into a visualizer, and the setArr function sets the element of arr into NULL. I know that NULL is 0 in C. But I cannot connect why and how element of arr can be set to NULL.
Can any one explain to my why, in this case, I cannot use x[2][2] as a parameter to receive arr.
Because you are using wildly different types. int *arr[2]; is an array of 2 int*, each of them assigned to an allocated chunk of memory. That's a lookup table or "jagged array" if you will, not a proper 2D array. See Correctly allocating multi-dimensional arrays for details.
Correct code for allocating a 2D array is this:
#include <stdlib.h>
void setArr(int a, int b, int x[a][b])
{
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
x[i][j] = 0;
}
int main(void)
{
int (*arr)[2] = malloc(sizeof(int[2][2]));
setArr(2, 2, arr);
free(arr);
}
Here arr in main is a pointer to the first element of an int[2][2]. The first element of that 2D array is int[2], and a pointer to such an element is int(*)[2].
Function declaration void setArr(int x[2][2], int a, int b) declares setArr as a function that takes as a first parameter an array of 2 arrays each holding 2 integers. Whereas in the main you declare arr (the variable you pass to setArr) as int *arr[2], that is as a pointer to an array of 2 integers.
The solution is to either change your code in main, for example by declaring arr as int arr[2][2] and remove the for loop, or change the setArr so that it takes a pointer to an array of two integers void setArr(int *x[2], int a, int b).
I'm not sure if the latter could cause any problems (gcc -Wall compiles without warnings), but one thing to notice is the difference in memory layout when declaring arr as a pointer to an array of size 2 or declaring it as an array of 2 arrays of size 2. Compiling and executing the following should show you the difference:
int main(void) {
int *arr[2];
for (int i = 0; i < 2; i++) {
arr[i] = malloc(sizeof(int) * 2);
}
printf("The address of arr[0] is %p\n", &arr[0]);
printf("The address of arr[1] is %p\n\n", &arr[1]);
printf("The address of arr[0][0] is %p\n", &arr[0][0]);
printf("The address of arr[0][1] is %p\n", &arr[0][1]);
printf("The address of arr[1][0] is %p\n", &arr[1][0]);
printf("The address of arr[1][1] is %p\n\n", &arr[1][1]);
int arr2[2][2];
printf("The address of arr2[0] is %p\n", &arr2[0]);
printf("The address of arr2[1] is %p\n\n", &arr2[1]);
printf("The address of arr2[0][0] is %p\n", &arr2[0][0]);
printf("The address of arr2[0][1] is %p\n", &arr2[0][1]);
printf("The address of arr2[1][0] is %p\n", &arr2[1][0]);
printf("The address of arr2[1][1] is %p\n", &arr2[1][1]);
// setArr(arr, 2, 2);
}
Running the executable once on my machine I got the following:
The address of arr[0] is 0x7ffe43d226b0
The address of arr[1] is 0x7ffe43d226b8
The address of arr[0][0] is 0xb62010
The address of arr[0][1] is 0xb62014
The address of arr[1][0] is 0xb62030
The address of arr[1][1] is 0xb62034
The address of arr2[0] is 0x7ffe43d226c0
The address of arr2[1] is 0x7ffe43d226c8
The address of arr2[0][0] is 0x7ffe43d226c0
The address of arr2[0][1] is 0x7ffe43d226c4
The address of arr2[1][0] is 0x7ffe43d226c8
The address of arr2[1][1] is 0x7ffe43d226cc
You can see that the when declaring arr as an pointer to an array, the two arrays of two integers are not contiguous, whereas when declaring it as an array of arrays, they are. Moreover, when declaring it as an array of arrays there is no need to dynamically allocate memory (e.g., using malloc).
x[2][2] is just a declaration of a variable; there is no need to declare a var in input of a function; you must declare it before and just use its address:
void setArr(int** x, int a, int b)

What does happen when we equation two pointer in C?

This is a C code to sort the substrings of a large string starting from each index but I cannot understand how can we sort the array a in the code.
As far as I understand:
we refer a[i] to &c[i] and thus it created n arrays but doesn't
&a[i][1] == &a[i+1][0]?
Since a[i] = &c[i], is it true that &a[i][0] == &c[i]?
If not, this looks like a faster way to create n(length of original
string) arrays, without actually copying it. Is that true?
My code
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define M 1
#define MAXN 5000000
char c[MAXN], *a[MAXN];
int pstrcmp(char **p, char **q){
return strcmp(*p, *q);
}
int main(){
int i, ch, n = 0, maxi, maxlen = -1;
while ((ch = getchar()) != EOF) {
a[n] = &c[n];
c[n++] = ch;
}
c[n] = 0;
qsort(a, n, sizeof(char *), pstrcmp);
printf("%s",a[1]);
return 0;
}
I'm guessing pstrcmp is a wrapper around strcmp that compares two pointers to char pointers. Something like:
int pstrcmp(const void *a, const void *b) {
return strcmp(*(char**)a, *(char**)b);
}
To answer your questions,
Yes, &a[i][1] == &a[i+1][0]. They both point to the i + 1-st character of c.
Yes, &a[i][0] == &c[i].
You are indeed creating pointers to n strings, but there is a catch: if you altered any string (say, the last character), you would be altering more strings. So these strings are not independent.
Conceptually, a[i] is a pointer to the suffix of c starting at position i. The program then sorts a according to the values of the strings they point to. So, for c = "abacaba", you would get { "a", "aba", "abacaba", "acaba", "ba", "bacaba", "caba" }.
Please note that there are faster ways to build suffix arrays.
In this code, I don't see sub-strings, as you don't build any.
Technically, a is an array of pointers of type char that could make it an array of strings, but the way you link c to a, effectively a is an index of c.
Inside the loop, you fill the index char by char. Later when you sort a, you sort the index.
The problem with the index is, that you can't really print it out as a string, as it is not a char * that the %s printf format modifier expects, but a char **. This alone should warn you about something spooky. I see that you evaded this problem as hard coding a[1] as parameter, but the sole problem of what index to use, tells, that you are going in the wrong way.
I've slightly edited your code, how it would print out the sorted array. If you think it is not doing what you want, there is a misunderstanding between what you want and what your code does (except the last printf).
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MAXN 5000000
// This is an array of characters:
char c[MAXN];
// This is an array of pointers pointing to individual characters. Essentially, this is an index.
char *a[MAXN];
static int pstrcmp(const void *p1, const void *p2){
// wrapper between strcmp and qsort's compare signature.
// See: man 3 qsort -- http://linux.die.net/man/3/qsort
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
int main() {
int ch;
size_t n = 0;
while ((ch = getchar()) != EOF) {
// In this loop, you systematically build up an index, where a[i] points to c[i].
a[n] = &c[n];
c[n] = ch;
n++;
}
c[n] = 0;
qsort(a, n, sizeof(char *), pstrcmp); // Now, you sort the _index_.
printf("\nc: %s\n", c); // Print Original array.
printf("a: "); // Print Ordered array:
for (size_t i = 0; i < n; i++)
printf("%c", *a[i]); // Look at the indirection
printf("\n");
return 0;
}

Function with return type array in C

I have the following function in C:
int[] function(int a){
int * var = (int*)malloc(sizeof(int)*tags);
....
}
*var is it a pointer to an array var?
If yes, how can I return the array (var) in the function?
You can't really return an array from a function, but a pointer:
int * function(int a){
int * var = malloc(sizeof(int)*tags);
//....
return var;
}
This code below could clarify a bit how array and pointers works.
The function will allocate memory for "tags" int variables, then it will initialize each element with a number and return the memory segment that points to the array.
From the main function we will cycle and print the array element, then we will free the no longer needed memory.
#include <stdio.h>
#include <stdlib.h>
int *function(unsigned int tags) {
int i;
int *var = malloc(sizeof(int)*tags);
for (i=0; i < tags; i++) {
var[i] = i;
}
return var;
}
int main() {
int *x;
int i;
x = function(10);
for (i=0; i < 10; i++) {
printf("TEST: %i\n", x[i]);
}
free(x); x=NULL;
return 0;
}
How about:
int* function(int tags){
int * var = malloc(sizeof(int)*tags);
//....
return var;
}
Arrays and pointers to the base element type are (mostly) synonymous in C/C++, so you can return a pointer to the first element of an array and use that as if it was the array itself.
Note, your code has an input parameter a, but using tags to allocate the memory for the array. I assumed in the above code that you wanted to use the input parameter for that purpose
Also, you will have to call free() on the pointer returned by function above, when you are no longer using the array, to avoid memory leaks. malloc above allocates memory enough to hold tags number of ints, so the array is equivalent to int var[tags];
UPDATE: removed cast for malloc's return
In C, functions cannot return array types. For your purposes, you want to return a pointer to int:
int *function(int a)
{
int *var = malloc(sizeof *var * tags); // where is tags defined?
// are you sure you don't mean a here?
...
return var;
}
This will allocate a block of memory large enough to hold tags integer values and assign the address of the first element of that block to var. Note that var is a pointer to int, not a pointer to an array of int. That pointer is what gets returned from the function.
You can use the subscript oprerator on a pointer expression as though it were an array, like so:
int a = ...;
int *arr = function(a);
...
arr[0] = 0;
arr[1] = 1;
...
arr is a pointer expression, not an array expression, so sizeof arr will return the size of the pointer type, not the size of the block of memory that it points to (because of this, you will want to keep track of the number of elements you allocated separately).
In C an array is basically the same type as a pointer to an element of the array.
So char[] is basically char*
Don't forget to keep track of the size of the array, also I noticed that tags seems to be a global variable, most of the time it's a good idea to avoid global variables
Here is some example code:
#include <stdio.h>
#include <stdlib.h>
int* foo(size_t arrSize){
int* arr = (int*) malloc(sizeof(int)*arrSize);
return arr;
}
int main (int argc, char** argv){
printf("Printing array:\n");
int* arr = foo(42);
for(int i=0; i <42; i++){
arr[i]=i;
}
for (int i=0; i < 42; i++){
printf("Element: %d: %d\n", i, arr[i]);
}
free(arr);
return 0;
}

Resources