I'm trying to have a function set a global variable to the value that i pass it. I know how to do this with something like an int, but i can't seem to get it to work with a string array. Here is the code:
#include "stdio.h"
char *(*(*foo));
void setFunc(char *arr[]);
int main(int argc, char const *argv[]) {
char *bar[] = {"Test", "Test 2"};
setFunc(bar);
printf("%s %s\n", *foo[0], *foo[1]);
return 0;
}
void setFunc(char *arr[])
{
foo = &arr;
}
This outputs: "Test (null)" And is as close as i could get.
I hope i am not missing something stupid. I am pretty new to C and pointers are still pretty confusing.
You do not need the third * on your global definition of foo. You should change it to char** foo;
char* bar[] is defining a pointer to an array of chars.
Assigning foo = arr (instead of foo = &arr) will assign the address of the pointer foo to be the same location as arr.
You can then change your print line to:
printf("%s %s\n", foo[0], foo[1]);
I think the difficulties come with
char ***foo;
and how that may lead to ambiguity with the variable
*foo[0]
. The computer does not know whether you mean:
(*foo)[0]
or:
*(foo[0])
. These calls to the foo variable will yield different results. You want:
(*foo)[0]
which dereferences foo to the array of char*'s, and then takes the first element of that array, and prints it.
I suggest taking out one of the pointers to make
char **foo;
This will make it easier to use, as you can just say:
foo[0]
without any ambiguity.
Related
I have such code:
typedef struct dArrString
{
char** arr;
int locLength;
int length;
} dArrString;
#define D_ARR_STRING(NAME, ARR_STRING)\
NAME.arr = (char**) malloc(0 * sizeof(char*))\
NAME.locLength = 2;\
NAME.length = 0;\
printf("%s", ARR_STRING[0]);
int main()
{
dArrString stos;
char emptyStr = {'\0'};
D_ARR_STRING(;stos, emptyStr);
return 0;
}
Problem is in ARR_STRING[0] in D_ARR_STRING macros, becuse after compiling this code I got such an error:
error: subscripted value is neither array nor pointer nor vector
printf("%s", ARR_STRING[0]);
How can I fix this or what should I change to?
ARR_STRING is the second parameter to the macro, which is passed as emptyStr.
emptyStr is declared as a char:
char emptyStr = {'\0'};
meaning that it is one single Character (like A, or Z).
The compiler is correct that you are trying to take the subscript ([ ]) of emptyStr, and emptyStr is not an array, nor a pointer, nor a vector.
If you want to fix it, you need to make the second parameter an array.
Most probably, you want:
char emptyStr[50] = ""; // I'm not sure what size you need, so I made it 50.
List of problems:
You have a weird semi-colon before stos for no clear reason.
You are calling malloc for 0 bytes.
You are treating variable emptyStr, a single char, like its an array of characters.
You have a substantial block of code in a macro for no good reason, when a function would do just fine.
It seems there are many questions of the form "should I declare X?" but not this specific one. I hope it is ok to ask this.
The title says it all: why should I declare a pointer? Even better: there are risks if I do not declare the pointer? Consider the following examples:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <string.h>
void func(int *ptr);
int main (int argc, char **argv)
{
int a;
int *PTRa;
a = -1;
PTRa = &a;
func(PTRa);
printf("%d\n", a);
return 0;
}
void func(int *ptr)
{
*ptr = 1;
return;
}
I get a=1. In this case I would say the pointer is declared (and assigned as well): I have the line int *PTRa; (declaration) and the line PTRa = &a; (assignment). The results is correct. I don't get any warning.
Imagine now to replace the main with the following:
int main (int argc, char **argv)
{
int a;
a = -1;
func(&a);
printf("%d\n", a);
return 0;
}
Here I do not declare the pointer but just give the address of a to func. The result is correct and I don't get warnings.
My understanding is that the two approaches are identical: func always gets the same input, the address of a. I would even dare to say that I feel the second approach to be better, as I feel it to be clearer and I feel the variable PTRa to be useless and somewhat redundant. However, I always see codes where the first approach is used and I have the feeling I will be told to do so. Why?
You are correct: there's no point in declaring a pointer in your example. A pointer is just a variable that holds an address. The cleaner approach is to pass directly the address of the variable: func(&a) instead of doing one extra step and declaring PTRa.
Note that not all cases are this simple. For example, if you want to have an array of ints, but you want to be able to grow that array dynamically because you don't know how big it should be you have to declare a pointer:
int count = ...; // get the count from the user, from a file, etc
int *list_of_ints = malloc(sizeof(int) * count);
if (list_of_ints == NULL)
{
// malloc failed.
printf("Not enough memory!\n");
exit(1);
}
// Now `list_of_ints` has enough space to store exactly `count` `int`s
EDIT: as #paulsm4 pointed out in a comment, the question Why use pointers? is a great source of information related to this topic.
EDIT 2: one good reason to want a pointer to the address of a variable might be that you want a pointer inside a structure or array:
struct foo
{
int x;
};
struct bar
{
int y;
struct foo f;
};
struct bar b;
struct foo *ptr_foo = &b.f;
You can now work more easily with b.f because you're just working with a struct foo.
In this case there's no benefit in creating a separate pointer variable.
It might be necessary in more complex cases, just like it's sometimes necessary to create variables of any other type.
From the title, I thought you're talking about pointer type, but actually, you are asking if declaring a variable is needed.
Variable is a piece of memory, storing some numbers(bytes), and the type of the variable, indicating how you and your program interpret those bytes: integer? float? character? etc.
Pointer is the memory address, it could be of a variable, or a function, or something else.
A variable of pointer is a small area in the memory, storing the address of other(or even same) memory.
You decide if you need an extra variable to store the pointer. It's the same to the decision that if you want a variable to store an integer:
int v = -1;
abs(v); // use variable
abs(-1); // use constant
In my code I need to pass a pointer to an array of pointers as a function argument. Code snippets:
struct foo * foos[] = {NULL, NULL, NULL};
some_function(&foos);
and:
static void some_function(struct foo ** foos) {
foos[0] = get_a_foo();
/* some more code here */
}
This works as expected (after some_function() returns, foos[] contains the pointers I set there), but I get a compiler warning for the call to some_function():
note: expected ‘struct foo **’ but argument is of type ‘struct foo * (*)[3]’
What’s the correct way to accomplish what I want (i.e. pass a pointer to the array of pointers to the function, so that the function can change pointers in the array)?
Pass it as some_function(foos)
struct foo ** is a pointer to a (single) pointer to a struct foo, not a pointer to an array of pointers, hence the compiler warning.
An easy way to silence the compiler warning is to call the function as follows:
some_function(&foos[0]);
This will pass a pointer to the first member, i.e. a struct foo **, rather than to the whole array; the address is the same in both cases.
If I understand what you are trying to do (fill your array of pointers with a call to a function), then your understanding of how to accomplish that is a bit unclear. You declare foos, which itself is an array. (an array of what? pointers).
You can treat it just like you would treat an array of char (from the standpoint that you can simply pass the array itself as a parameter to a function and operate on the array within a function) You can do that and have the changes visible in the caller because despite the array address itself being a copy in the function, the values it holds (the individual pointer address) remains the same.
For example:
#include <stdio.h>
char *labels[] = { "my", "dog", "has", "fleas" };
void fillfoos (char **f, int n)
{
int i;
for (i = 0; i < n; i++)
f[i] = labels[i];
}
int main (void) {
char *foos[] = { NULL, NULL, NULL };
int i, n = sizeof foos / sizeof *foos;
fillfoos (foos, n);
for (i = 0; i < n; i++)
printf ("foos[%d] : %s\n", i, foos[i]);
return 0;
}
Above foos is simply treated as an array passed to the function fillfoos which then loops over each pointer within foos filling it with the address to the corresponding string-literal contained in labels. The contents of foos is then available back in main, e.g.
Example Use/Output
$ ./bin/fillptp
foos[0] : my
foos[1] : dog
foos[2] : has
If I misunderstood your question, please let me know and I'm happy to help further.
You need a pointer to an array as clearly mentioned in the warning.
Below is a minimal code sample that explains the same.
#include<stdio.h>
typedef struct foo{
}FOO;
static void some_function(FOO* (*foos)[]) {
// foos above is a pointer to an array of pointers.
// Refer the link to start with a simple example.
// Access it like foos[0][0] which is the same as (*foos)[0]
/* some more code here */
}
int main(int argc, char **argv) {
FOO* foos[]={0,0,0}; // Here you have an array of pointers
some_function(&foos);
}
I understand why this does not work:
int main(int argc, char *argv[]) {
char *names[] = {"name1", "name2", "name3", "name4"};
int i = 0;
while (i++ <= 3) {
printf("%s\n", *names++);
}
}
Error:
a.c: In function 'main':
a.c:16: error: wrong type argument to increment
shell returned 1
It's because I am trying to increment an array variable (and NOT a pointer). Please don't mind the line number in the error message, I have lot's of commented code above and below what I have put up here.
However, I do not understand why this piece of code works:
void myfunc(char *names[]) {
int i = 0;
while (i++ <= 3) {
printf("%s\n", *names++);
}
}
int main(int argc, char *argv[]) {
char *names[] = {"name1", "name2", "name3", "name4"};
myfunc(names);
}
How can we increment names in myfunc()? It's still a local array variable in myfunc().
Could someone please help?
Thanks.
In the 1st example names is an array. Arrays cannot be incremented.
In the 2nd example names is a pointer. Pointers can be incremented.
Background to why the 2nd example compiles:
A [] in a variable definition in a function declaration is the same as (another) *.
So this
void myfunc(char * names[]);
is equivalent to
void myfunc(char ** names);
The latter makes it obvious that here names is not an array but a pointer.
When you pass an array as a function argument, it turns it into a pointer to the first element in the array. This means that when you declare an array and attempt to increment it directly, you are trying to increment an array. When you pass the array as an argument, on the other hand, it is passed as a pointer, so you can increment it.
If you wish to pass the array as an array, and not as a pointer, you might consider using std::array, which is a fixed size container.
EDIT: I apologise. std::array is only available in C++.
When you pass array to a function it decays into pointer.
Refer here to know about array-decaying
I want to store result of type char in pointer which I'm passing as argument of function. Like this:
#include<stdio.h>
void try(char *);
int main()
{
char *result;
try(result);
printf("%s",result);
return 0;
}
void try(char *result)
{
result="try this";
}
But I'm getting result : (null)
Could someone tell me what's wrong here?
Your syntax only sends the pointer to the function. This allows changing the data the pointer points to, but not the pointer itself.
You would need to have
void try(char **result)
and call it
try(&result);
to change the actual pointer.
Another way is to copy data into the memory pointed by the pointer, but then you need to know there is enough memory available. Depends on the actual use case how to do it properly. You might use
strcpy(result, "what you want");
but then you really have to know that the memory pointed by result can handle 14 chars (remember the NULL in the end). In your current code you don't allocate memory at all for result, so this will invoke undefined behaviour.
The reason you're seeing NULL is because your compiler decided to initialize non-assigned pointers to NULL. Another compiler might initialize them to random values.
Also about terminology, you're not storing type char into a pointer. You may have a pointer pointing to a char, or in this case to a C type string, which is an array of chars.
You are creating another variable result inside try function.
Try printing result inside try function. It will work then.
If you really want to print inside main then try this -
#include<stdio.h>
void try(char **);
int main()
{
char *result;
try(&result);
printf("%s",result);
return 0;
}
void try(char** result)
{
*result = "try this";
//printf("%s\n",result);
}
Or if you don't want to get into double pointers, then this will work:
#include<stdio.h>
char* try(char *);
int main()
{
char *result;
result = try(result);
printf("%s",result);
return 0;
}
char* try(char* result)
{
result = "try this";
return result;
}
Also another way (no dynamic memory):
#include<stdio.h>
void try(char *);
int main()
{
char result[100] = {0};
try(result);
printf("%s",result);
return 0;
}
void try(char *result)
{
strcpy(result,"try this");
}
Note: When you say you got null, that doesn't mean anything - actually you had undefined behaviour there - because result was not initialized. I guess you invoked UB even before trying to print result, namely when you passed it to try. Because copy would be made in that method of the pointer, which would try to read value of original pointer - reading uninitialized variables is undefined in C. Hence always initialize your variables in C.