Pass a char pointer array to a function in C? - c

I have the following code:
int main(){
char **array;
char a[5];
int n = 5;
array = malloc(n *sizeof *array);
/*Some code to assign array values*/
test(a, array);
return 0;
}
int test(char s1, char **s2){
if(strcmp(s1, s2[0]) != 0)
return 1;
return 0;
}
I'm trying to pass char and char pointer array to a function, but the above code results in the following errors and warnings:
temp.c: In function ‘main’:
temp.c:6:5: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
temp.c:6:13: warning: incompatible implicit declaration of built-in function ‘malloc’ [enabled by default]
temp.c:10:5: warning: implicit declaration of function ‘test’ [-Wimplicit-function-declaration]
temp.c: At top level:
temp.c:15:5: error: conflicting types for ‘test’
temp.c:15:1: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
temp.c:10:5: note: previous implicit declaration of ‘test’ was here
temp.c: In function ‘test’:
temp.c:16:5: warning: implicit declaration of function ‘strcmp’ [-Wimplicit-function-declaration]
I'm trying to understand what the problem is.

First of all, you should include the necessary header files. For strcmp you need <string.h>, for malloc <malloc.h>. Also you need to at least declare test before main. If you do this you'll notice the following error:
temp.c: In function ‘test’:
temp.c:20:5: warning: passing argument 1 of ‘strcmp’ makes pointer from integer without a cast [enabled by default]
/usr/include/string.h:143:12: note: expected ‘const char *’ but argument is of type ‘char’
This indicates that test() should have a char * as first argument. All in all your code should look like this:
#include <string.h> /* for strcmp */
#include <malloc.h> /* for malloc */
int test(char*,char**); /* added declaration */
int main(){
char **array;
char a[5];
int n = 5;
array = malloc(sizeof(*array));
array[0] = malloc(n * sizeof(**array));
/*Some code to assign array values*/
test(a, array);
free(*array); /* free the not longer needed memory */
free(array);
return 0;
}
int test(char * s1, char **s2){ /* changed to char* */
if(strcmp(s1, s2[0]) != 0) /* have a look at the comment after the code */
return 1;
return 0;
}
Edit
Please notice that strcmp works with null-terminated byte strings. If neither s1 nor s2 contain a null byte the call in test will result in a segmentation fault:
[1] 14940 segmentation fault (core dumped) ./a.out
Either make sure that both contain a null byte '\0', or use strncmp and change the signature of test:
int test(char * s1, char **s2, unsigned count){
if(strncmp(s1, s2[0], count) != 0)
return 1;
return 0;
}
/* don' forget to change the declaration to
int test(char*,char**,unsigned)
and call it with test(a,array,min(sizeof(a),n))
*/
Also your allocation of memory is wrong. array is a char**. You allocate memory for *array which is itself a char*. You never allocate memory for this specific pointer, you're missing array[0] = malloc(n*sizeof(**array)):
array = malloc(sizeof(*array));
*array = malloc(n * sizeof(**array));

Error 1
temp.c:6:13: warning: incompatible implicit declaration of
built-in function ‘malloc’ [enabled by default]
Did you mean this?
array = malloc(n * sizeof(*array));
Error 2
temp.c:15:5: error: conflicting types for ‘test’
temp.c:15:1: note: an argument type that has a default promotion can’t
match an empty parameter name list declaration
temp.c:10:5: note: previous implicit declaration of ‘test’ was here
You are passing the address of the first element of an array a:
test(a, array);
So the function signature should be:
int test(char* s1, char** s2)

You have several problems. The first is that the prototype is wrong. The data type for a decays to a char pointer when passing to a function, so you need:
int test (char* s1, char** s2) { ... }
However, even when you fix this, the test declaration isn't in scope when you first use it. You should either provide a prototype:
int test (char* s1, char** s2);
before main, or simply move the whole definition (function) to before main.
In addition, don't forget to #include the string.h and stdlib.h headers so that the prototypes for strcmp and malloc are available as well.

When you pass an array of char to your function, the argument decays to a pointer. Change your function arguments to
int test(char* s1, char **s2);
^
^
and your code should at least compile

Related

correct return type for C function?

I am using an array of strings inside my function declared like this
char (*array)[PATH_MAX] = malloc (1000 * sizeof *array);
Allocating 1000 char pointers of size PATH_MAX (1024).
I want the function to return that specific data structure, i.e. return the pointer array. But I can't manage to choose the correct return type.
warning: returning 'char (*)[1024]' from a function with return type 'int' makes integer from pointer without a cast [-Wint-conversion]
I get that I can't have int as return type, but char** doesn't work either.
warning: returning 'char (*)[1024]' from a function with incompatible return type 'char **' [-Wincompatible-pointer-types]
I've tried using char (*)[1024] as return type, but it gives me generic C error messages, leading me to believe that I am not using the correct syntax.
error: expected identifier or '(' before ')' token
38 | char (*)[1024] read_dir (char *path) {
| ^
Is there a correct syntax for achieving this or am I just doing it wrong?
You need to define the function as follows:
char (*read_dir(char *path))[PATH_MAX] {
This specifies the return type as a pointer to an array of size PATH_MAX of char *.
Time for typedef
typedef char arr1k_char[1000];
arr1k_char *foo(int n) {
arr1k_char *x = malloc(n * sizeof *x);
return x;
}
https://ideone.com/Cqxa61

Void** as parameter requires cast

I have a function in C that needs to receive a pointer to an array (with an unspecified type).
To do so, I use void**, as I would use void* to receive an array of unspecified elements.
There's a problem unfortunately: the compiler gives a warning (passing argument 1 of 'f' from incompatible pointer type). If I ignore the warning, and try to execute the program, everything works as expected.
The only way to get rid of the warning is to cast whatever I try to pass to the function to void**.
Why does C behaves like that? And is there a better way to solve the warning?
PS: I need to compile using GCC with the flags -std=gnu89 -pedantic -Wall
Example
int f(void** param){ return 1; }
int main(){
int *arr = malloc(sizeof(int) * 20);
int i;
for(i=0; i < 20; i++) arr[i] = i;
f(&arr);
}
The pointer to anything type is void*, and the compiler will not complain about conversions to that type. But void** is not a pointer to anything, it's a pointer to an array of pointers to anything, which is quite different from a pointer to an array of pointers to integers, so the compiler complains.
So, to solve the warning, yes you would need to cast explicitly.
Although void * is the "generic pointer" in C, void ** isn't a "generic pointer to pointer". Instead, it's nothing more than the "specific pointer to void *, the generic pointer".
In your case, a int ** is converted implicitly to a void **, which is not generic. Since a void ** is not guaranteed to be able to hold all pointer variables (thus incompatible to a int **), the compiler raises a warning.
Here is the warning generated by clang:
main.c:7:7: warning: incompatible pointer types passing 'int **' to parameter of
type 'void **' [-Wincompatible-pointer-types]
f(&arr);
^~~~
main.c:1:14: note: passing argument to parameter 'param' here
int f(void** param){ return 1; }
To eliminate this warning, you can have int f(void* param);, and cast param to int ** inside the function. There will be no warning because a void * can be used to store any pointer (Quoted from N1570):
6.3.2.3 Pointers
1 A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
It seems that you want to modify the address of the data (not the value) inside the function, you can't do that directly with a void * because you can't use arithmetic with void *, but you can pass the size of the first element and a chunk of bytes (char *), suppose you want to change the address of arr to arr + 1 (the second element of the array) inside the function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f(void *ptr, size_t size)
{
// char *p = *ptr; Wrong, you can't dereference a void * without a cast
char *p = *(char **)ptr; /* pointer to address of ptr */
memmove(p, p + size, size); /* assign the address of ptr + 1 to ptr */
}
int main(void)
{
int *arr = malloc(sizeof(int) * 20);
int i;
for (i = 0; i < 20; i++) arr[i] = i;
f(&arr, sizeof arr[0]);
printf("%d\n", arr[0]);
return 0;
}
Output:
1

what is wrong in this strcmp()?

I try to write simple C function with strcmp(). But I always get Segmentation fault (core dumped). What is wrong ?
char *arr={"abcdefg"};
char *a = arr[1];
if(strcmp(a, 'b') == 0)
{
printf("it is b \n");
}
What is wrong?
You did not let yourself be helped by the compiler.
Using -Wall -Wextra on GCC (which is by no means the best you can get but rather the bare minimum you should always use), I get:
testme.c: In function ‘main’:
testme.c:6:11: warning: initialization makes pointer from integer without a cast [enabled by default]
char *a = arr[1];
^
You took arr[1] -- which is the char value 'b' -- and turned it into a char *. Your a is now pointing to whatever is at address 0x62 (assuming ASCII), which is most definitely not what you intended. You probably wanted &arr[1], or arr + 1.
Or you wanted a char -- then you shouldn't declare char *, and strcmp() would be the wrong thing to use in the first place.
testme.c:8:1: warning: passing argument 2 of ‘strcmp’ makes pointer from integer without a cast [enabled by default]
if(strcmp(a, 'b') == 0)
^
In file included from testme.c:1:0:
/usr/include/string.h:144:12: note: expected ‘const char *’ but argument is of type ‘int’
extern int strcmp (const char *__s1, const char *__s2)
^
strcmp() expects two C strings (char const *). Your second argument 'b' is of type int... you probably wanted "b".
Which still would not compare equal, because "bcdefg" is not equal "b"...
Or you wanted a one-character comparison... that would be if ( a == 'b' ) then, with a being of type char, not char * (see above).
testme.c:10:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
printf("it is b \n");
^
testme.c:10:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
Please do us all the favour of posting complete code, includes, int main() and all, so we can copy & paste & compile, and still have line numbers match.
I think this is what you have been trying to achieve :
#include <stdio.h>
#include <string.h>
int main(void)
{
char *arr = {"abcdefg"};
char a = arr[1];
if( a == 'b' )
{
printf("it is b \n");
}
}
You're doing a number of things wrong here. strcmp is for comparing strings. The simplest way to do what you want is
char *arr= {"abcdefg"};
char a = arr[1];
if(a == 'b')
{
printf("it is b \n");
}
If you still want to do it with strcmp, you need to make a a string by appending the null terminator \0 to it.
char *arr= {"abcdefg"};
char a[] = {arr[1], '\0'};
if(strcmp(a, "b") == 0)
{
printf("it is b \n");
}

Initialization from incompatible pointer type [enabled by default] - whats wrong?

I have this warning in my code:
initialization from incompatible pointer type [enabled by default]
code is as follows:
/*
* Method return some number :-)
* It is TEST METHOD
*/
int check(char array[]) {
int num = 0; // my number
char **elem_p = array; // test
while (*elem_p) { // it is while
num++;
elem_p++;
}
return num; // my return
}
What is wrong? How can I fix this?
Thank you. Test method is not relevant, is a sample.
What is wrong?
array is of type char * (pointer to char) but you are using it to initialize char ** (pointer to pointer to char) type variable elem_p.
How can I fix this?
Make pointer and pointee (object to be pointed) compatible to each other. Declare elem_p as char *;
char *elem_p = array;
char array[] will be rewritten as char* array. You either need char* array[] or char** array, but there is no difference in a function declaration. You probably intended to only have one asterisk, as haccks points out.
char* array[]) {
int num = 0; // my number
char **elem_p = array; // test
I think you meant char *elem_p = array;. For more information, see 'Pointers and Arrays' at http://www.cplusplus.com/doc/tutorial/pointers/.

Segmentation fault error in gcc

Why the following code is giving segmentation fault error
#include<stdio.h>
int main()
{
int i;
int a[2][2]={1,2,3,4};
int **c;
c=a;
for(i=0;i<4;i++)
printf("%d",*(*(c)+i));
}
This assignment:
c=a;
Should give you a warning. a decays into a pointer to its first element, which has type int (*)[2]. Assigning that type to a variable of type int ** requires an explicit cast.
Redeclaring c should fix your problem:
int (*c)[2];
Example warning from clang:
example.c:8:6: warning: incompatible pointer types assigning to 'int **' from
'int [2][2]' [-Wincompatible-pointer-types]
c=a;
^~
1 warning generated.
Read the comments of the following code:
#include<stdio.h>
int main()
{
int i;
int a[2][2]={{1,2},{3,4}}; // Put each dimension in its braces
/*int a[2][2]={1,2,3,4};
This declaration of array make the following:
a1[ONE] a2[TWO] THREE FOUR
a3[Unknown value] a4[Unknown value]
i.e. the numbers 3 and 4 are being written beyond of the array...
*/
int *c1;
int **c2; // `int **` is a pointer to a pointer, so you have to
c1=&a[0][0]; // declare a pointer `c1` and then assign to it `c2`.
c2=&c1; // AND use `&` to assing to pointer the address of
// variable, not its value.
for(i=0;i<4;i++)
printf("%d",*(*(c2)+i)); // here is `double dereference` so here must be `c2`
// (ptr-to-ptr-to-int) but not c1 (ptr-to-int).
return 0; // AND make the `main()` to return an `int` or
// make the returning type `void`: `void main(){}`
// to make the `main()` function to return nothing.
}
This is a problem in the definition of c. int **c; Suggests that this is a pointer to a pointer, but the definition of a is of type int *[2]. Changing the definition of c to int (*c)[2] should do the trick.

Resources