Pass char** as an argument to a function in C - c

I know there are many topics of this kind but I've read several of them and still can't figure out what am I doing wrong.
I've successfully generated a char** array. My bubble sort function probably works as well. But when I passed the generated array to the function, only 1 row is copied.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
void sort(char** tab)
{
char* temp;
int i, j, size = sizeof(tab)/sizeof(tab[0]);
printf("%d\n", size);
for(i = 0; i < size; ++i)
{
for(j = i+1; j < size; ++j)
{
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
}
}
for(i = 0; i < sizeof(tab)/sizeof(tab[0]); ++i)
puts(tab[i]);
}
int main()
{
srand(time(NULL));
int size = rand()%5+5, i, j, s;
char** tab = (char**)malloc(size * sizeof(char*));
for(i = 0; i < size; ++i)
{
s = rand()%9+1;
tab[i] = (char*)malloc(s+1);
for(j = 0; j < s; ++j)
tab[i][j] = 'a'+rand()%26;
tab[i][s] = 0;
}
for(i = 0; i < size; ++i)
puts(tab[i]);
puts("");
sort(tab);
return 0;
}
Here's how the code works.
And when I write size=5 before the loop in the function it returns segmentation fault.
Edit: Same with passing the size of the array as an argument:
http://ideone.com/3Wvncq
Final code
I've fixed all the problems and here's the final code.
I was misinterpreting segmentation fault as the result of assigning a fixed size instead of not allocating the temp variable.
Thank you for all the answers.

Don't calculate size inside function void sort(char** tab) . As in this function it will be calculated as -
int i, j, size = sizeof(tab)/sizeof(tab[0]); // equivalent to sizeof(char **)/sizeof(char*) in function giving wrong length as you desire.
It's length in main(size is generated using rand so no need to find it) and then pass it as argument to function sort.
Declare your function like this -
void sort(char** tab,size_t size)
And while calling from main pass length of tab to it -
sort(tab,size); // size will be number of elements in tab calculated in main
You get segmentation fault because of this -
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
temp is uninitialized in sort and still you pass it to strcpy thus undefined behaviour . Initialize temp before passing to strcpy.Allocate memory to temp in function sort.

In your sort function you declare the temp variable:
char* temp;
Later you use it as destination (and source) for string copying:
strcpy(temp, tab[j-1]),
But nowhere in between do you make temp point anywhere, temp is uninitialized and that leads to undefined behavior and your crash.
Don't use a pointer, instead declare it as an array of the largest string size possible.

Related

Dynamically allocating space for a 2D array

I am a novice C programmer trying to write a function that dynamically allocates space for a 2D array. I am getting a segmentation fault when running this code & i'm not sure why.
#include <stdio.h>
#include <stdlib.h>
int allocate_space_2D_array(int **arr, int r, int c) {
int i,j;
arr = malloc(sizeof(int *) * r);
for (i = 0; i < r; i++)
arr[i] = malloc(sizeof(int *) * c);
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%p", arr[r][c]);
}
printf("\n");
}
return arr;
}
I expected to be able to print out and see the contiguous memory locations of each spot in the array, but I am never reaching that point in my code, because when I run it, i get a segmentation fault. Would appreciate any help.
Seeing your program i see 3 errors one while you allocate memory for 2D-array,one while you're printing and another one is how you declare the function.
First malloc is ok,the second one is wrong cause you already allocated memory for r(size of row) pointers so it's just like if you have * arr[r],so to allocate memory correctly now you should allocate memory just for int and not for int*.
Second error while printing you put as index for row and column the values r and c,but r and c are the size of matrix , as we know the size of an array or 2D-array goes from 0 to size-1,in your case goes from 0 to r-1 and from 0 to c-1.
Third error you should declare the function not as int but as int** cause you want to return a matrix so the return type is not int but int**.
I change your code to make it work correctly,it should be work.
int** allocate_space_2D_array(int **arr, int r, int c) {
int i,j;
arr = malloc(sizeof(int *) * r);
for (i = 0; i < r; i++)
arr[i] = malloc(sizeof(int ) * c);
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%p", arr[i][j]);
}
printf("\n");
}
return arr;
}

Possible to run through a c-array inside a function with only one pointer as parameter?

I'm playing and learning a little with C, created an array and passed it to a function together with its size so I can run through the array and print all its elements (so I gave the function two parameters: the array itself and its size).
But now I like to do all that just by passing one parameter to the function. I got it working a little by using a pointer but I don't know how to stop because I don't have any information about arrays length, it only works in the code below because I put the array length inside the for loop. But how would that work in general if I didn't know the size and only passed one parameter to the function?
I thought it might somehow be possible to realize if a pointer points outside of the array I'm currently working with, but is that even doable? :S
void printArray(int *p){
for(int i=0; i<4; i++){
printf("%d ", *(p+i));
}
}
int main(){
int myArray[4] = {8,4,1,1};
int *p = myArray;
printArray(p);
return 0;
}
The only way to traverse a pointed-to array without a length parameter is if the array contains a distinct terminator value.
For example, a C-string is "NULL-terminated" array of char values. You can traverse a char* because you know
to test for the presence of the '\0' character, which has an integer value of 0.
As it applies to the code in your question, you could use -1 as a terminator value, like so:
void printArray(int *p){
while (*p != -1{
printf("%d ", *p++);
}
}
Note however, that doing this requires that there is some way to interpret a valid int value as
"invalid" for your purposes.
In the main, it's much easier and simpler to just pass the length of the array to the function.
In addition to other mentioned approaches I can offer other two:
1) You can pass the length of array as the first element (like works some containers in Pascal):
#include <stdio.h>
void print_array(int *arr)
{
int length = arr[0];
for (int index = 1; index <= length; ++index)
printf("%d ", arr[index]);
printf("\n");
}
int main()
{
int length = 10;
int *arr = malloc(sizeof(int) * length);
arr[0] = length;
for (int index = 1; index <= length; ++index)
arr[index] = index * index * index;
print_array(arr);
free(arr);
return 0;
}
2) You can create a struct for your array (like is is done for std::vector in C++ STD with class):
#include <stdio.h>
typedef struct Array
{
int size;
int *data;
} Array;
void print_array(Array *arr)
{
for (int index = 0; index < arr->size; ++index)
printf("%d ", arr->data[index]);
printf("\n");
}
int main()
{
int length = 10;
Array *arr = malloc(sizeof(Array));
arr->data = malloc(sizeof(int) * length);
arr->size = length;
for (int index = 0; index < length; ++index)
arr->data[index] = index * index * index;
print_array(arr);
free(arr->data);
free(arr);
return 0;
}

Segmentation fault when accessing a 2D array in a structure whose pointer is returned from a function

I made a structure who has two members (int and int**), and I return the pointer to this structure from one function to main(). It is fine to access the int value in the structure. However, in main() I got Segmentation fault : 11 when I tried to access the element of the 2D array.
#include<stdio.h>
#include<stdlib.h>
typedef struct Square {
int value;
int **array;
} Square;
Square * generate();
int main(int argc, char *argv[]){
Square *sqrptr = generate();
printf("%d\n", sqrptr -> value);
/* It prints 1 */
/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3 ; j++){
printf("%d ", *(*((sqrptr -> array) + i) + j));
}
printf("\n");
}
/* It gives segmentation fault */
return 0;
}
Square * generate(){
Square mySquare;
mySquare.value = 1;
mySquare.array = malloc(sizeof(int*) * 3);
/* Initialize the 2D array */
for (int i = 0; i < 3; i++){
*(mySquare.array + i) = malloc(sizeof(int) * 3);
for (int j = 0; j < 3; j++){
*(*(mySquare.array + i) + j) = 0;
}
}
/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3l ; j++){
printf("%d ", *(*(mySquare.array + i) + j));
}
printf("\n");
}
/* I can see the complete 2D array here */
Square *sqrptr = &mySquare;
return sqrptr;
}
I have tried to generate the Square in main(), and use one pointer of the structure to access my 2D array. It works fine, so I guess I have missed something when I use a pointer returned from other functions. On the other hand, I can access the int value successfully, so I have no clues now.
Could someone please explain the underlying reason for this segmentation fault? Thanks!
You're returning a pointer to a local variable (&mySquare). Stack memory (where local variables reside) is when the function returns, so the resulting pointer is pointing to invalid memory. Allocate the struct, and return the pointer to heap memory:
Square *my_square = malloc(sizeof *my_square);
//do stuff
return my_square;
Or pass a pointer to a stack variable as argument:
Square * generate(Square *my_square)
{
//in case pointer wasn't provided, allocate
if (my_square == NULL) {
my_square = malloc(sizeof *my_square);
if (!my_square)
return NULL; // or exit or whatever
}
//initialize members. To initialize array to 3x3 zero matrix, you can use:
for (int i=0;i<3;++i)
my_square.array[i] = calloc(3, sizeof *my_square->array[i]);
//or even, if you change array member to type int*:
my_square.array = calloc(3*3, sizeof *my_square->array);
//at the end:
return my_square;
}
The latter is arguably the most flexible solution: if you want to work on stack, you call the function like so:
Square my_stack_square;
generate(&my_stack_square);
If you need to use heap memory, you can use:
Square *my_heap_square = generate(NULL);
As Jonathan Leffler pointed out, for a small struct such as this, returning by value isn't too much of a cost. Getting a struct on heap can be achieved in the same way as returning any other type:
Square generate( void )
{
Square my_square;
//initialize
return my_square;
}
//call like so:
Square sq = generate();
The idea here is that you'll use a local variable in the generate function to create a new square, initialize the fields, and then return it. Because in C everything is passed by value, this essentially means the function will assign the value of the local variable from the generate function to the caller's scoped sq variable. For small structs such as this, that's perfectly fine.
What's more, a common thing for compilers to do is to optimise these kinds of functions to the equivalent of the second example I posted: Essentially your function will be creating a new Sqaure object on the stack memory of the caller. This can happen, that's not to say it will. It depends on the optimization levels used when compiling, and on the size of the struct you're returning.
Basically, if you want to keep the code as close to what you have now, it's probably easiest to stick to the first version (returning a heap pointer).
The more flexible approach is the second one (as it allows you to use stack and heap, depending on how you call the function).
For now, using the third approach is perfectly fine: the compiler will most likely optimize the code to whatever makes most sense anyway.
Try this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct Square {
int value;
int **array;
} Square;
Square * generate();
int main(int argc, char *argv[]){
Square *sqrptr = generate();
printf("%d\n", sqrptr -> value);
/* It prints 1 */
/* Print out the 2D array */
int i,j;
for (i = 0; i < 3; i++){
for (j = 0; j < 3 ; j++){
printf("%d ", *(*((sqrptr -> array) + i) + j));
}
printf("\n");
}
/* It gives segmentation fault */
return 0;
}
Square * generate(){
Square* mySquare = (Square*) malloc(sizeof(Square)); //c++ compiler
//Square* mySquare = (void*) malloc(sizeof(Square)); //c compiler
mySquare->value = 1;
mySquare->array = malloc(sizeof(int*) * 3);
/* Initialize the 2D array */
int i,j;
for (i = 0; i < 3; i++){
*(mySquare->array + i) = malloc(sizeof(int) * 3);
for (j = 0; j < 3; j++){
*(*(mySquare->array + i) + j) = 0;
}
}
/* Print out the 2D array */
for (i = 0; i < 3; i++){
for (j = 0; j < 3l ; j++){
printf("%d ", *(*(mySquare->array + i) + j));
}
printf("\n");
}
/* I can see the complete 2D array here */
return mySquare;
}

C: adding elements to an array

I'm trying to test a program that creates an array with 0 elements in it, then adds elements to it (reallocating memory each time), and then printing out the elements. But, I keep getting errors when I try to run it.
int main(int argc, const char * argv[]) {
int num = 0;
int n = 10;
int **array = malloc(0);
for (int i = 0; i < n; ++i)
{
++num;
array = realloc(array, num * sizeof(int*));
array[num-1] = &i;
}
for (int j = 0; j < n; ++j)
{
printf("%d", &array[j]); // error 1
}
return 0;
}
I'm sorry I didn't include the errors with the original post. I think I fixed one of them. Here is the other:
Error 1: Format specifies type 'int' but the argument has type 'int *'
This answer is based on the assumption that you are printing a simple array, since you don't show what output you expect. You are using one more step of indirection than you need, and too many variables. Take note that indexing is different from length (often by 1).
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i, n = 10;
int *array = NULL; // no need for double star, or fake allocation
for (i = 0; i < n; ++i)
{
array = realloc(array, (i + 1) * sizeof(int)); // remove the *, add 1 for num elements
array[i] = i;
}
for (i = 0; i < n; ++i)
{
printf("%d", array[i]); // remove the &
}
free(array); // don't forget this
return 0;
}
Program output:
0123456789
In practice, you should assign the result of realloc to another pointer variable, check it's ok, and then replace the original pointer var.
printf("%d", &array[j]); // error 1
The & is the address operator. So it is making something a pointer. Your array is already an array of pointers to integer.
By using the & you are trying to print the address of the integer pointer itself.
Try using * instead of &. * means that you want to print the value of the integer pointer.
printf("%d", *array[j]); // error 1

find number of rows in a 2D char array

How to find number of rows in dynamic 2D char array in C?
Nothing from there.
tried with following code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int k = 97;
void foo(char **a)
{
int i = 0;
for(i=0; a[i] != NULL; ++i)
printf("i = %d\n", i);
}
void strcpyo(char* a, char*b){
int i=0;
for(i=0;b[i]!='\0';i++){
a[i]=b[i];
}
a[i]='\0';
}
void strcpym(char* a, char*b){
int i=0;
for(i=0;b[i]!='\0';i++);
memcpy(a,b,i+1);
}
void freee(char** ptr){
int i;
for(i = 0;i < k; ++i)
{
free(ptr[i] );
}
free(ptr);
}
void alloc(char ***p)
{
*p = (char **)malloc(k * sizeof(char *));
int i,j;
for(j=0;j<k;j++)
{
// for(i = 0;i < j; ++i)
{
(*p)[j] = (char *)malloc(11 * sizeof(char));
strcpy((*p)[j],"paicharan");
}
//printf("j = %d ", j);
//foo(p);
}
}
int main()
{
char **p;
alloc(&p);
#if 0
char **p = (char **)malloc(k * sizeof(char *));
int i,j;
for(j=0;j<k;j++)
{
for(i = 0;i < j; ++i)
{
p[i] = (char *)malloc(11 * sizeof(char));
strcpy(p[i],"paicharan");
}
printf("j = %d ", j);
foo(p);
}
#endif
foo(p);
freee(p);
return 0;
}
The code in #if 0 #endif works perfectly, but if I do create arrays in function alloc(char**) it's giving the wrong answer for odd number of rows in array. Can anybody explain why?
ie. for k= odd number it gives out wrong answer but for even number its correct.
Your code depends on Undefined Behaviour to work correctly i.e. it'll work only by chance. This has got nothing to do with even or odd count of elements.
In the void alloc(char ***p) function you allocate memory for k pointer to pointer to char: char**. Then you fill all of the k pointers with new valid char* pointers i.e. none of them are NULL. Later in void foo(char **a) you do for(i=0; a[i] != NULL; ++i); since a[k - 1] was non-null, it'll iterate over them correctly. BUT after that a[k] may or may not be NULL, you never know what is in there. Also accessing what is beyond the array you allocated is undefined behaviour (due to out of bounds access).
Making k + 1 elements and setting the kth element to NULL makes this work; make sure you free all of k + 1 elements and not leak the last sentinal element.
Since you told that the code wraped inside the macro works fine, I've ignored that; don't know if there's UB there too. If you're doing this exercise to learn, it's fine. If you are planning to do some other project, try to reuse some existing C library which already gives these facilities.

Resources