Pointers On Pointers - c

#include <stdio.h>
#include <string.h>
void F1(void *comp, void *record){
int complen = strlen((char *)comp), recordlen = *(int *)record;
*(int *)record = complen>recordlen ? complen : recordlen;
}
void F2(void *comp, void *ans){
if(!*(char **)ans)
*(char **)ans = (char *)comp;
else if(strcmp((char *)comp, *(char **)ans) < 0)
*(char **)ans = (char *)comp;
}
void ProcessStrings(char ***vals, void* (*fp)(char *, void *), void *champ){
char **copy = *vals;
while(*copy){
fp(*copy++, champ);
}
}
int main() {
char *strings1[][100] = {{"beta", "alpha", "gamma", "delta", NULL}, {"Johnson", "Smith", "Smithson", "Zimmerman", "Jones", NULL}, {"Mary", "Bill", "Bob", "Zoe", "Annabelle", "Bobby", "Anna", NULL}};
int maxLen = 0;
char *minString = NULL;
ProcessStrings(strings1, F1, &maxLen);
ProcessStrings(strings1, F2, &minString);
printf("Strings1: Max length is %d and min is %s\n", maxLen, minString);
}
A quick background...function F1 supplies the max length of a list of strings to it's second parameter. F2 supplies the minimum string in terms of ASCII value.
My error message states that I'm passing an incompatible pointer type to process strings. When I draw out the pointers, I feel as though I am not. Help?

You are passing an incompatible pointer type indeed.
strings1 is a 2D array of pointers to chars. Note, that a 2D array elements in C are laid out sequentially row after row, while the function expects to see a pointer after the first dereference of strings1 inside the ProcessStrings.
If you want you code to work correctly, you need to either pass the following construct to ProcessStrings
char **strings2[] = {
strings1[0],
strings1[1],
strings2[2]
};
or to change the the function to work with a pointer to an array of 100 char pointers:
void ProcessStrings2(char * (*vals)[100], void (*fp)(void *, void *), void *champ){
Btw, your function seems to process only the first row of strings.

Related

How to reverse every string in an array of strings through a function in C?

I have been trying to solve this issue for whole day, and could not do it on my own. Searching the internet didn't help me solve it either
So, this the function prototype:
void invert(char **arr, int n);
First argument is an array of strings, and the second one is number of strings in an array.
This is my code:
#include <stdio.h>
#include <string.h>
void invert(char** arr, int n)
{
int i, j, len;
for(j=0;j<n;j++)
{
len=strlen(arr[j]);
for(i=0;i<len/2;i++)
{
char tmp = arr[j][i];
arr[j][i] = arr[j][len - i - 1];
arr[j][len - i - 1] = tmp;
}
}
}
int main()
{
int n=3, i;
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
}
The code breaks when it reaches the line:
arr[j][i] = arr[j][len - i - 1];
and I can't figure out why.
The function receives an array of strings perfectly (tested it with some printf statements for characters of specific strings), and the char tmp succesfully recieves a correct character, but the program crashed when it reaches the line mentioned earlier. Printf statements after that line don't work.
Did I miss anything? Can someone explain what am I doing wrong? Thank you!
For starters this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invokes undefined behavior because the pointer arr is uninitialized and has an indeterminate value.
Moreover this approach in any case is wrong because you may not change string literals.
What you need is to declare a two-dimensional array as for example
enum { N = 11 };
//...
char arr[3][N] =
{
"John", "Doe", "Programmer"
};
In this case the function declaration will look like
void invert( char arr[][N], int n );
The enumeration must be declared before the function declaration.
Instead of the two-dimensional array you could declare an array of pointers like
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
In this case the function declaration may be as shown in your question
void invert(char** arr, int n)
So what you need to do with minimal changes is to substitute this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
for this code snippet
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
To begin with, what you have here:
char **arr;
is a pointer to pointer to char.
Secondly, even if you had an array of pointers to char, like so :
char *arr[3];
And then assigning each string literal :
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
would still invoke Undefined behavior, since you are attempting to modify a string literal which is read only.
What you need is, either a 2D array of chars :
char arr[][100] = {"John", "Doe", "Programmer"};
and also change the function signature to :
void invert(char arr[][100], int n)
or you have to dynamically allocate memory and use a function like strcpy(), strdup(), memcpy() etc :
char **arr;
arr = malloc(n * sizeof(char *)); // or sizeof(*arr)
if (arr == NULL) {
fprintf(stderr, "Malloc failed to allocate memory\n");
exit(1);
}
arr[0] = strdup("John"); // good idea to also check if strdup returned null
arr[1] = strdup("Doe");
arr[2] = strdup("Programmer");
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
for (i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);

Pointer to function Prototype

i am trying to figure out what those prototypes mean
1.int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
2.int* (*fpData[2])(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (* fpCalculation[3]) (const char *));
3.int* (*(*fpData)(const char *))(int (*paIndex)[3] ,
int (* fpMsg) (const char *),
int (* fpCalculation[3]) (const char *));
First you should find actual variable which is being declared. In all 3 examples this is fpData. Then you should start to read declaration staring from this variable moving from inside to outside.
So, let us begin with first example. We see fpData, so we say "fpData is...", then we see "*" before "fpData", so we say "fpData is pointer to...", then we see function type declaration outside of *fpData, so we say "fpData is pointer to function...". Then we should read types of arguments and result of this function.
Well, you can read types for all 3 arguments without problems. They are:
"paIndex is pointer to array of length 3 of ints"
"fpMsg is pointer to function from const char * to int"
"fpCalculation is array of length 3 of pointers to function from const char * to int"
In the last argument you should note that [3] has the higher priority than "*". I mean that while reading declaration from inside to outside you should read first array and then pointer. I. e. int *a[3] is "a is array of length 3 of pointers of int" and not "pointer to array".
Assuming all this I think you can read 2nd declaration without problems.
Now you should learn this: type of function result is written outside (i. e. BEFORE AND AFTER) of everything else.
Let us consider this:
char (*(*fp)(int))(double)
What this means? Well let's start reading, "fp is pointer to function which takes int and returns... what?" Well, we already have read (*fp)(int) part. Now we want to read everything else. And we want to understand what is result type of function we already read. And now we should note that result of function is the thing which is written OUTSIDE (i. e. BEFORE and AFTER) of everything else, i. e. outside of what we already read.
So, we have read (*fp)(int). Everything else, i. e. char (*XXX)(double) is return type for function we already read. So, well, let's continue reading. Finally we will get this:
"fp is pointer to function which gets int and returns pointer to function which gets double and returns char".
Now you can read 3rd declaration without problems
The C gibberish ↔ English link that chux posted still looks like gibberish to
me. So I'll try to sound more human:
int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
This declares a function pointer fpData that returns a pointer to int. The
function takes 3 variables of the following types:
paIndex is a pointer to an int array of dimension 3. This can be used for
example when you have this:
void bar(int (*paIndex)[3])
{
}
void foo(void)
{
int fields[5][3] = { {1,1,1}, ... };
bar(fields);
}
fpMsg is a function pointer that returns an int. The function takes one
arguments only, a const char* (a string basically).
fpCalculation is an array of dimension 3 of function pointers that return
int. The functions take on argument only: a const char*.
This is a beast of a function pointer, it works in an evironment like this:
#include <stdio.h>
int msg(const char *name)
{
printf("msg: %s\n", name);
return 0;
}
int abc1(const char *name)
{
printf("abc1: %s\n", name);
return 0;
}
int abc2(const char *name)
{
printf("abc2: %s\n", name);
return 0;
}
int *scary_function(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *))
{
fpMsg("fpMsg");
fpCalculation[0]("fpCalculation0");
fpCalculation[1]("fpCalculation1");
fpCalculation[2]("fpCalculation2");
for(int i = 0; i < 4; ++i)
{
for(int j = 0; j < 3; ++j)
{
printf("%-3d ", paIndex[i][j]);
}
puts("");
}
return NULL;
}
void foo(void)
{
int matrix[4][3] = { {1,2,3}, {4,5,6}, {7,8,9}, {10,11,12} };
int (*fpcalcs[3])(const char*) = { msg, abc1, abc2 };
int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
fpData = scary_function;
// calling the function through the function pointer
fpData(matrix, msg, fpcalcs);
}
int main(void)
{
foo();
return 0;
}
The output of this is
msg: fpMsg
msg: fpCalculation0
abc1: fpCalculation1
abc2: fpCalculation2
1 2 3
4 5 6
7 8 9
10 11 12
So I've explained in detail how to parse the declaration of these function
pointers. Now try understanding the other 2 yourself, if you still have problems,
post a comment.
1.int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *), int (*fpCalculation[3]) (const char *));
Here, fpdata is pointer to a function which takes three arguments and returns a pointer to an integer. The arguments are as follows:
pointer to 3 elements integer array,
pointer to a function which takes const char pointer as an argument and return type int,
array of 3 function pointers and each function takes const char pointer as an argument and return type is int
2.int* (*fpData[2])(int (*paIndex)[3] , int (* fpMsg) (const char *), int (* fpCalculation[3]) (const char *));
In this case, fpdata is array of 2 function pointers, and each function takes three arguments -
pointer to 3 elements integer array,
pointer to a function which takes const char pointer as an argument and return type int,
array of 3 function pointers and each function takes const char pointer as an argument and return type is int
The return type is a pointer to an integer
3.int* (*(*fpData)(const char *))(int (*paIndex)[3] , int (* fpMsg) (const char *), int (* fpCalculation[3]) (const char *));
Finally, fpdata is a pointer to a function which takes three arguments -
pointer to 3 elements integer array,
pointer to a function which takes const char pointer as an argument and return type int,
array of 3 function pointers and each function takes const char pointer as an argument and return type is int
The return type is a function pointer which takes const char pointer as argument and return type is pointer to an integer.
int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
it is function prototype declaration.
Where fpData is a function name, function that takes three arguments:
int (*paIndex)[3]
int (* fpMsg) (const char *)
int (*fpCalculation[3]) (const char *)
…and returns a function pointer [pointer to a function that take no argument but returns pointer to an integer].
Details :: Given function can be written as below
typedef int* (*ret_func_ptr) ();
ret_func_ptr (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));

Assigning and retrieving an array of strings to a void pointer

I'm quite unfamiliar with how pointers work. I'm working with a function that callbacks a function with a void * context as an argument.
How would I go about assigning an array of strings to a void * and then retrieving them?
char callback_value[2][16];
snprintf(callback_value[0], sizeof(callback_value[0]), "string1");
snprintf(callback_value[1], sizeof(callback_value[1]), "string2");
// pass an array of strings into the void * callback context
void *callback_context = callback_value;
// Illustration only, doesn't work
// retrieve it here
char **retrieved_strings = (char **)callback_context;
printf("%s", retrieved_strings[0]); // Want "string1"
printf("%s", retrieved_strings[1]); // Want "string2"
#include <stdio.h>
void func(void* arg)
{
char (*tmp)[16] = arg;
printf("%s\n%s\n", tmp[0], tmp[1]);
}
int main(void)
{
char callback_value[2][16] = {"string1", "string2"};
void *callback_context = callback_value;
func(callback_context);
return 0;
}
char** is not compatible with char[2][16], you have to use a pointer to an array of char char (*)[16].
https://ideone.com/BqgeN6

Why this qsort() doesn't work?

Am sorting an array of strings (case insensitive).
qsort causes segmentation fault, probably my casting isn't proper.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(const void *string1, const void *string2) {
char *a = (char*)(string1);
char *b = (char*)(string2);
printf("comparing %s AND %s\n", a, b);
return strcasecmp(a,b);
}
void sortListName(char **fileList, int noOfFiles) {
printf("Sorting\n");
qsort(fileList, noOfFiles, 260*sizeof(char), compare);
return;
}
**fileList = array of strings (filenames)
P.S. main() is obvious and works fine.
If this is all the code you have related to the qsort, it looks like you declared the comparePtr function pointer, but it's still not initialized; it's not pointing to your compare function (which is what I assume you wanted it to point to).
After that, a few more things:
1) comparePtr has the correct types, but compare does not. It needs to take in two const void*, but you have two const void**.
2) Once you fix the types, you could just pass compare to qsort, instead of making a function pointer and passing that.
3) I'm not convinced the first argument to qsort is correct. You want to be passing in the pointer to the first element in the array, which ought to just be fileList (I'm assuming it points to the first string in your array).
4) The third argument isn't correct either. fileList is a char**, meaning you're passing in an array of char *s, and hence the third argument should just be sizeof(char*), not the strlens of the strings.
I would adjust things so that you're just sorting a simple array, in this case of pointers to char - qsort will arrange for you to get pointers to two elements in that array (that is, char ** pointers), and some basic dereferencing is needed to get you to the "pointers to char" comparable via strcasecmp. #Mark likely has sussed out the source of the 260 in your unseen calling code, but I'm not a big fan of those kinds of 2d arrays in C.
The following functions for me, with an example main() to exercise it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(const void *v1, const void *v2){
char *a = *(char **)v1;
char *b = *(char **)v2;
printf("comparing %s to %s\n", a, b);
return strcasecmp(a,b);
}
void sortListName(char **fileList, int noOfFiles){
printf("Sorting\n");
qsort(fileList, noOfFiles, sizeof(*fileList), compare);
return;
}
int
main(void)
{
char *filenames[] = {
"/var/www/icons/comp.gray.png",
"/var/www/error/HTTP_SERVICE_UNAVAILABLE.html.var",
"/var/www/icons/right.gif",
"/var/www/error/HTTP_NOT_IMPLEMENTED.html.var",
"/var/www/icons/pie3.png",
"/var/www/icons/pie2.png",
"/var/www/htdocs/manual/mod/mod_proxy_balancer.html",
"/var/www/htdocs/manual/programs/rotatelogs.html",
"/var/www/htdocs/manual/vhosts/mass.html",
"/var/www/icons/movie.png",
"/var/www/htdocs/manual/images/caching_fig1.png",
"/var/www/htdocs/htdig/search.html",
"/var/www/icons/generic.gif",
"/var/www/htdocs/manual/mod/quickreference.html",
"/var/www/icons/small/blank.png",
"/var/www/icons/image2.gif"
};
int i, nf = (int) (sizeof(filenames) / sizeof(filenames[0]));
puts("Unsorted:");
for (i = 0; i < nf; i++) {
puts(filenames[i]);
}
sortListName(filenames, nf);
puts("Sorted:");
for (i = 0; i < nf; i++) {
puts(filenames[i]);
}
return 0;
}

convert pointer to pointer to void pointer

When I'm learning to use qsort to sort an array of string, there is a question puzzled me.
For example, to sort the following s
char *s[] = {
"Amit",
"Garima",
"Gaurav",
"Vaibhav"
};
To use the qsort, you must provide a comparison function like the
following function cstring_cmp I guess in the qsort function, the type of parameter to be passed to the function cstring_cmp is char**. How to convert a char** to a void*? Why can we convert a char** to a void*?
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return -strcasecmp(*ia, *ib);
/* return the negative of the normal comparison */
}
Your question seems a bit vague but I'll give it a go anyway. To answer how, you can convert any pointer type to any other pointer type in C by simply casting. To answer why, well that's how C is defined.
The qsort() function requires a function with the given prototype (with const void *) parameters. This is because qsort() is unaware of the actual data type you are sorting, and must use a consistent function prototype for the comparison callback. Your comparison callback is responsible for converting the const void * parameters to pointers to the actual types in your array, in your case const char **.
The example you provide is being setup to ask qsort() to sort an array of char pointers (char *). This comparator you're providing is given each 'pair' of items the algorithm needs, by address. two char pointers. the address qsort() uses is based on the root address you give it, adding size-bytes per "item". Since each "item" is a char*, the size of each item is, in fact, the size of a pointer.
I've modified the comparator to demonstrate what is being compared, and what the addresses are that are being passed in. you will see they are all increments off the base address of the array containing all the char *s.
char *mystrings[] =
{
"This",
"is",
"a",
"test",
"of",
"pointers",
"to",
"strings"
};
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
printf("%p:%s - %p:%s\n", a, *ia, b, *ib);
return -strcasecmp(*ia, *ib);
}
int main(int argc, char *argv[])
{
printf("Base address of our pointer array: %p\n\n", mystrings);
qsort(mystrings, sizeof(mystrings)/sizeof(mystrings[0]), sizeof(char*), cstring_cmp);
for (size_t i=0; i<sizeof(mystrings)/sizeof(mystrings[0]);i++)
printf("%s\n", mystrings[i]);
return 0;
}
produces the following output:
Base address of our pointer array: 0x100006240
0x100006240:This - 0x100006260:of
0x100006260:of - 0x100006278:strings
0x100006240:This - 0x100006278:strings
0x100006248:is - 0x100006240:strings
0x100006278:This - 0x100006240:strings
0x100006250:a - 0x100006240:strings
0x100006270:to - 0x100006240:strings
0x100006258:test - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006268:pointers - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006240:test - 0x100006248:This
0x100006248:test - 0x100006250:to
0x100006240:This - 0x100006248:to
0x100006260:of - 0x100006268:pointers
0x100006268:of - 0x100006270:a
0x100006270:a - 0x100006278:is
0x100006268:of - 0x100006270:is
to
This
test
strings
pointers
of
is
a
A even less visualized one:
int cstring_cmp(const void *a, const void *b){
return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}
But you can see , a and b are char **, and they are dereferenced and become char * and passed to strcasecmp.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int cstring_cmp(const void *a, const void *b){
return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}
int main(){
char *s[] = { "Amit",
"Garima",
"Vaibhav",
"Gaurav"};
qsort(s, 4, sizeof(char *), cstring_cmp);
printf("%s\n%s\n%s\n%s\n", s[0], s[1], s[2], s[3]);
return 0;
}
Output:
Vaibhav
Gaurav
Garima
Amit
It is legal to cast any pointer to char * or void * because void * means a pointer to a memory (RAM or virtual) byte.

Resources