Confusing pointers and arrays in C - c

I'm trying to understand the mistake in the following code. The code is supposed to switch between two arrays.
What I saw is that it switches only the first 4 bytes. Is the following correct?
Passing &num1 or num1 is the same (both pass the address of the first element in the array).
The (char**) casting is wrong. That's because when you pass and array you pass the address it's laid in. So you actually pass here a void*.
How can I actually switch between these two arrays only by pointers? Is thatpossible?
I know it is possible if from the beginning I had defined char **num1 and char **num2. But I want it to stay with the array notation!
#include <stdio.h>
void fastSwap (char **i, char **d)
{
char *t = *d;
*d = *i;
*i = t;
}
int main ()
{
char num1[] = "hello";
char num2[] = "class";
fastSwap ((char**)&num1,(char**)&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
return 0;
}

Passing &num1 or num1 is the same (both pass the address of the first element in the array). Am I correct?
No. The first one is a pointer to the array itself (of type char (*)[6]), whereas in the second case, you have a pointer to the first element (of type char *; an array decays into a pointer to its first element when passed to a function).
The (char*) casting is wrong
Indeed, you are casting a char (*)[6] to a char **.
So you actualy pass here a void (Am i correct?).
No. Non sequitur. I don't see how the void type is relevant here. You have pointers, arrays, and eventually pointers to arrays.
Arrays are not pointers. Your code is trying to swap arrays, which does not make sense, since assignment to arrays is not permitted. What you probably want is
I. either get pointers to the first character of each string, and then swap the pointers themselves, like this:
void swap_pointers(const char **a, const char **b)
{
const char *tmp = *b;
*b = *a;
*a = tmp;
}
const char *p1 = "hello";
const char *p2 = "world";
swap_pointers(&p1, &p2);
II. Or use actual arrays, and you swap their contents:
void swap_contents(char *a, char *b, size_t n)
{
for (size_t i = 0; i < n; i++) {
char tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
char a1[] = "hello";
char a2[] = "world";
swap_contents(a1, a2, strlen(a1));
Also, you may want to read this.

1. Passing &num1 or num1 is the same (both pass the address of the first element in the array)
Not true, &num1 gives you a pointer to a pointer that points to the entire character string "hello" (char*[6]) while num1 is just a pointer to the character block "hello" (char[6]).
2. The (char*) casting is wrong. That's because When you pass and array you pass the address it's laid in. So you actualy pass here a void (Am i correct?).
It is still not a void, it's just a pointer to a character pointer. If it were void, then it would be perfectly valid to do something like void** myVoid = &num1. This will cause a syntax error unless you explicitly typecast your char** to a void** before you assign it.
The problem is your explicit type casting &num1 as a char** which is not correct, it is a char*[6]. But of course, you can't declare a variable as a char*[6] so it can't be used in this way. To fix it you need to declare your num1 and num2 as:
char* num1 = "hello";
char* num2 = "class";
instead and keep everything else the same. In fact, with this change there is no need to typecast your &num1 as a char** because it already is that.

Related

Trying to print a string in a qsort function

I'm having some trouble passing a valid value to the qsort function but can't quite figure out what's going wrong with it. Here is what I have so far:
int main(void)
{
char* strings[4] = {"Onus", "deacon", "Alex", "zebra"};
printf("%zu\n", sizeof(strings));
qsort(strings, 4, 8, scmp);
}
int scmp(const void *p1, const void *p2)
{
printf("%s\n", (char*) p1);
return 0;
// ignore return value -- I'm just looking to print the string.
}
It just seems to print gibberish when I do this. Is this because qsort expects a value a pointer to a value and I'm passing it a pointer to a (char) pointer? What would be the correct way to reference it then?
It seems instead it should be: printf("%s\n", *(char* const*) p1); ? This is from some trial-and-error, though not sure why that works -- i.e., the *(char**).
For example, for passing an int I can do:
const int *v1 = p1;
But then a char* needs to be:
const char *s1 = *(char* const *) p1;
Why not just const char *s1 = (char*) p1; ?
strings is an array of pointers to char. The comparison function for qsort gets passed pointers to the two elements of the array that should be compared. Since the elements of the array are pointers to char, the arguments p1, p2 to scmp are pointers to (const) pointers to char, and should be cast to char ** (or rather char * const *).
What needs to be passed to printf is the pointer to char itself, so you have to dereference the argument to get that pointer. If you wanted to look at the individual characters of the string, you'd have to dereference again. There are two *s in the name of the type, so you have to apply * two times to get back to the underlying primitive type.
printf("The first character of the string is %c\n", **(char * const *)p1);

c - swapping strings pass by value rather than reference?

I made a code to swap two strings:
void swap (char *a, char *b)
{
char *t = a;
a = b;
b = t;
}
int main()
{
char * strings[2];
strings [0] = "luck!";
strings [1] = "good ";
swap (strings[0], strings[1]);
printf( "%s %s\n",strings[0], strings[1]);
return 0;
}
And it fails. What i have trouble understanding is when i call swap() i pass two pointers. Both pointers point to the first character of their assigned arrays. I then created a temporary pointer inside the function and perform basic switch. What is flawed here? I really want to understand why this approach is wrong?
You are switching the parameters of the function, which are local to the function scope. When your function is executed, the parameters (a, of type char*, and b, of type char*) are passed by value, put on the stack, and the function is executed. The parameters are modified and then popped of the stack without effect.
To make a difference, you need to pass references to the parameters:
void swap (char **a, char **b)
{
char *t = *a;
*a = *b;
*b = t;
}
and then call with:
swap (&strings[0], &strings[1]);
You now pass pointers to individual array elements in strings, which is in main's stack segment and thereby persists past the context of swap.
You pass a copy to the pointers to the function and thus you exchange the copies. In C you will have to pass a pointer to the pointers to actually swap them.
If you want to swap values through pointers, you need to use assigments of the form
*a = *b;
If you would do that in your code, it would swap the first characters of the strings. To swap the pointers, you need to have paraemters of type char**, and pass &strings[0].
Just to give you example, about what other answers suggesting ...
Update your swap function to
void swap (char **a, char **b)
{
char *t = *a;
*a = *b;
*b = t;
}
And then call it in main as
swap(&strings[0], &strings[1]);
However, you may want to update assignment of strings as string like "luck!" is constant and you cannot update its individual characters.
strings [0] = strdup("luck!");
strings [1] = strdup("good ");

How Do you pass a pointer-to-an-array to a function?

How do you pass an array to a function where that function can edit it's contents?
like when doing
function(int *x)
{*x = 10;}
main()
{int x;
function(&x);}
how could i do the same using a character array?
whenever I do
function(char *array[], int *num)
{ int x = *num;
*array[x] = 'A'; }
main()
{ char this[5] = "00000"; //not a string
int x = 3;
function(&this, &x); }
DEV C++ says
[Warning] passing arg 1 of `function' from incompatible pointer type
obviously I did something wrong, so please tell me how to fix that. Thanks :D
You should write:
void function(char array[], int *num)
{
int x = *num;
array[x] = 'A';
}
void main()
{
char my_array[5] = "00000";
int x = 3;
function(my_array, &x);
}
Notation char *array[] is an array of pointers that you do not need here.
When you pass an array somewhere, you should not take its address. Arrays are adjusted to pointers by default.
EDIT:
Function prototypes:
void function(char array[], int *num);
void function(char *array, int *num);
are absolutely identical. There is no even minor difference between them.
Since arrays can only be passed by address, you don't really want a char * array here, just a char array:
rettype function(char *array, int *num)
{
array[*num] = 'A';
}
int main()
{
char arr[] = "1234567890";
int i = 2;
function(arr, &i);
}
In C, array names "devolve" to a pointer to the head of the array, by passing "&array", you're passing a pointer to a pointer to the head of the array, thus the warning.
char array[512];
myfunc(array, foo);
is the proper way to do what you want.
Actually you have taken one dimension array. So you can define function in two ways...
(i)
function(char array[], int *num)
{ int x = *num;
*array[x] = 'A'; }
main()
{ char this[5] = "00000"; //not a string
int x = 3;
function(this, &x); }
and
(ii)
function(char *array, int *num)
{ int x = *num;
*array[x] = 'A'; }
main()
{ char this[5] = "00000"; //not a string
int x = 3;
function(this, &x); }
But in your function definition, you wrote *array[] as argument which means the array is two dimensional array. So you should declare array as two dimensional array.
function(char *array[], int *num)
{ int x = *num;
//implement your code }
main()
{ char this[5][10];
// you can initialize this array.
int x = 3;
function(this, &x); }
I think it will be helpful to you.
Okay, the first thing to remember is that there's no such thing as a pointer "to an array" although you'll hear that said fairly often. It's sloppy.
(As pointed out below, the terminology "pointer to an array" does strictly have a meaning -- but I maintain that you've been confused by it. What really happens is that every pointer contains an address. Depending on the declaration, the compiler can identify if it's being used correctly in context, and that's what your error message is really telling you: what you declared in the function is a pointer to an array of chars, which is to say the same thing as a char **, instead of a char *, which is what you're passing. But char *, or char **, or char ******, the important point is that you're making it too complex -- you already have the address you need identified by the array name.)
Pointers is pointers, they're addresses.
An array in C is simply an allocated chunk of memory, and it's name represents the address of the first element. So
char a[42];
is a block of memory 42 char's long, and a is its address.
You could rewrite your second function as
void foo(char* a, int num){ // (3)
// notice that you don't need the word function and
// for lots of reasons I wouldn't use it as a function name.
a[num] = 'A'; // (4)
}
int main(){
// Sadly "00000" IS a string no matter what your comment
// says. Use an array initializer instead.
char arry[5] = {'0','0','0','0','0' } ; // (1)
foo(arry,3); // (2)
}
This does what I believe your code means to do. Note that
(1) Since "00000" really is a string, it's actually creating an array 6 elements long which could have been initialized with the array initializer
{'0','0','0','0','0', 0 }
(2) The array (which I named 'arry' instead of 'this' since 'this' is often a keyword in C-like languages, why risk confusion?) is already an address (but not a pointer. It can be on the right-hand side of an assignment to a pointer, but not on the left hand side.)
So when I call
foo(arry,3);
I'm calling foo with the address of the first element of arry, and the number 3 (you don't need to declare a variable for that.)
Now, I could have also written it as
foo(&arry[0],3);
You would read that as "find the 0-th element of arry, take its address." It is an identity in C that for any array
char c[len];
the expression c and &c[0] refer to the same address.
(3) that could also be defined as foo(char arry[], int num). Those are equivalent.
(4) and when you refer to a[num] you're referring directly to the num-th element of the memory pointed to by a, which is at the address of the start of the array arry. You don't need all that dereferencing.
Don't be disturbed that this is a little hard to follow -- it's tough for everyone when they start C.
Firstly dont use this as a variable name, its a C++ keyword. Sorry didnt realise it was a C question.
main()
{
char foo[5] = "00000"; //not a string
int x = 3;
function(foo, &x);
}
You dont take the memory address of foo. foo when used in a pointer-accepting context degrades into a pointer to the first element. *foo is the same as foo[0] which is the same as *(foo + 0)
like wise foo[3] is the same as *(foo + 3) (the compiler takes care of multiplying the element size).

Triple stars: What's the difference between char* (*arr)[] and char*** arr (in C)?

Basically, I have an array of char* that I want to pass and modify in this function, so I pass in a pointer to an array of char*. That is, I want to pass a pointer to char* arr[]. What is the difference between the two?
As always, http://cdecl.org is your friend:
char * (*arr)[] - "declare arr as pointer to array of pointer to char"
char *** arr - "declare arr as pointer to pointer to pointer to char"
These are not the same. For a start, the first is an incomplete type (in order to use a pointer to an array, the compiler needs to know the array size).
Your aim isn't entirely clear. I'm guessing that really all you want to do is modify the underlying data in your array of char *. If so, then you can just pass a pointer to the first element:
void my_func(char **pointers) {
pointers[3] = NULL; // Modify an element in the array
}
char *array_of_pointers[10];
// The following two lines are equivalent
my_func(&array_of_pointers[0]);
my_func(array_of_pointers);
If you really want to pass a pointer to an array, then something like this would work:
void my_func(char *(*ptr)[10]) {
(*ptr)[3] = NULL; // Modify an element in the array
}
char *array_of_pointers[10];
// Note how this is different to either of the calls in the first example
my_func(&array_of_pointers);
For more info on the important difference between arrays and pointers, see the dedicated chapter of the C FAQ: http://c-faq.com/aryptr/index.html.
If you have a function that has char *(*arr)[] as a parameter, you will need to pass in an array with the address operator:
void afunc(char *(*arr)[]);
char *charptra, *charptrb, *charptrc;
char *arr[] = {charptra, charptrb, charptrc};
afunc(&arr);
On the other one, you have to pass a pointer that points to a pointer that points to a pointer:
void afunc(char ***);
char arr[] = "str";
char *arrptr = arr;
char **arrptrptr = &arrptr;
char ***arrptrptrptr = &arrptrptr;
afunc(arrptrptrptr);

How to qsort an array of pointers to char in C?

Suppose I have an array of pointers to char in C:
char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
And I wish to sort this array using qsort:
qsort(data, 5, sizeof(char *), compare_function);
I am unable to come up with the compare function. For some reason this doesn't work:
int compare_function(const void *name1, const void *name2)
{
const char *name1_ = (const char *)name1;
const char *name2_ = (const char *)name2;
return strcmp(name1_, name2_);
}
I did a lot of searching and found that I had to use ** inside of qsort:
int compare_function(const void *name1, const void *name2)
{
const char *name1_ = *(const char **)name1;
const char *name2_ = *(const char **)name2;
return strcmp(name1_, name2_);
}
And this works.
Can anyone explain the use of *(const char **)name1 in this function? I don't understand it at all. Why the double pointer? Why didn't my original function work?
Thanks, Boda Cydo.
If it helps keep things straight in your head, the type that you should cast the pointers to in your comparator is the same as the original type of the data pointer you pass into qsort (that the qsort docs call base). But for qsort to be generic, it just handles everything as void*, regardless of what it "really" is.
So, if you're sorting an array of ints, then you will pass in an int* (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to int*, and dereference to get the int values that you actually compare.
Now replace int with char*:
if you're sorting an array of char*, then you will pass in a char** (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to char**, and dereference to get the char* values you actually compare.
In your example, because you're using an array, the char** that you pass in is the result of the array of char* "decaying" to a pointer to its first element. Since the first element is a char*, a pointer to it is a char**.
Imagine your data was double data[5] .
Your compare method would receive pointers (double*, passed as void*) to the elements (double).
Now replace double with char* again.
qsort is general enough to sort arrays consisting of other things than pointers. That's why the size parameter is there. It cannot pass the array elements to the comparison function directly, as it does not know at compile time how large they are. Therefore it passes pointers. In your case you get pointers to char *, char **.
The comparison function takes pointers to the type of object that's in the array you want to sort. Since the array contains char *, your comparison function takes pointers to char *, aka char **.
Maybe it is easier to give you an code example from me. I am trying to sort an array of TreeNodes and the first few lines of my comparator looks like:
int compareTreeNode(const void* tt1, const void* tt2) {
const TreeNode *t1, *t2;
t1=*(const TreeNode**)tt1;
t2=*(const TreeNode**)tt2;
After that you do your comparison using t1 and t2.
from man qsort:
The contents of the array are sorted in ascending
order according to a comparison function pointed to by
compar, which is called with two arguments that **point**
to the objects being compared.
So it sounds like the comparison function gets pointers to the array elements. Now a pointer to a char * is a char **
(i.e. a pointer to a pointer to a character).
char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
is a statement asking the compiler for an array of size 5 of character pointers. You have initialized those pointers to string literals, but to the compiler, it's still an array of five pointers.
When you pass that array into qsort, the array of pointers decays into a pointer pointing to the first element, in accordance with C array parameter passing rules.
Therefore you must process one level of indirection before you can get to the actual character arrays containing the constants.
#bodacydo here is a program that may explain what other programmers are trying to convey but this would be in context of "integers"
#include <stdio.h>
int main()
{
int i , j;
int *x[2] = {&i, &j};
i = 10; j = 20;
printf("in main() address of i = %p, address of j = %p \r\n", &i, &j);
fun(x);
fun(x + 1);
return 0;
}
void fun(int **ptr)
{
printf("value(it would be an address) of decayed element received = %p, double dereferenced value is %d \r\n",*ptr, **ptr);
printf("the decayed value can also be printed as *(int **)ptr = %p \r\n", *(int **)ptr );
}
qsort() passes a pointer to the user-defined comparison function and as you have a char * (pointer to char array) hence your comparison function should dereference from pointer to pointer hence char **.

Resources