Passing pointers to function - c

I have a doubt in my program
#include<stdio.h>
int myFunc(char **);
main()
{
char *a[2]={"Do","While"};
myFunc(a);
}
int myFunc(char **P)
{
/* Here I want to print the strings passed but I'm unable to
print the strings I just tried the below statement which
printed just the first letter which is 'D'*/
printf("%c",**P);
}
when i tried
printf("%s",**P);
I am getting run time error. so can anyone please help me out?
Thanks
Madhu

Put size as parameter to allow the function to know how many strings you have in your array. Then, you should iterate the array and print each one.
int myFunc( char** p, int size)
{
for( int i = 0; i < size; ++i)
{
printf("%s", p[i]);
}
}
Later edit (as requested :-) )
int main( int, char**)
{
char *a[2]={"Do","While"};
myFunc( a, 2); // Could be myFunc( a, sizeof(a)/sizeof(char*));
// ...
return 0;
}

Too many stars - try
printf("%s",*P);
And you need %s format specifier - %c is just for single character.
If you want to print all strings, you need to pass number of strings in array and then print these strings from the loop.
Check the code suggested by Cătălin Pitiș. To pass the number of strings, you call function like this:
myFunc(a, sizeof(a)/sizeof(a[0]));

for( int i = 0; i < 2; i++ ) {
char* string = P[i];
printf( "%s", string );
}
And you shoud use some way of passing size of array into the function - either pass it as an int parameter,
int myFunc(char **P, int size)
{
for( int i = 0; i < size; i++ ) {
//whatever here
}
}
or always append a zero value to the array and only loop until you find that zero value.
char* array[] = { "String1", "String2", 0 };
Otherwise you will have hard to maintain code.

I like objective-c style nil (0) terminated arrays:
void myFunc(char **P)
{
while (*P) // loop to iterate over all strings until 0
printf("%s\n",*P++); // print and move to next element in array
}
int main()
{
char *a[]={"Do","While",0}; // added 0 to null terminate array,
myFunc(a); // kind of like string
}
Output:
Do
While

First, the good news: the type of a is equivalent to char **, so you are passing a valid parameter to myFunc().
The first problem is that %c is a format specifier that means print a single character. Since **P is an expression that evaluates to a single character, your first version does exactly what you told it to do. That isn't what you want.
The second version is close to syntactically correct. It should read printf("%s", *P), where *P is an expression that evaluates to a pointer to a nul-terminated ASCII string. In this case, it evaluates to "Do". This version won't print both strings.
Although it is true that the name of an array is the same as a pointer to its first element, that is a kind of "lie to students". Passing an array to a function does not and cannot convey the length of the array. To do that, you need either a second argument containing the length, or a convention like the nul-terminator on a string to indicate the end of the array. With that change, you can modify myFunc() to use a loop over the elements passed and print each one.

The problem in your code is that you want to print a string (char*) but you're giving it a char. Remember that P is an array of char*. When you de-reference it once, you get a char*; when you do it a second time, you just get the char at the beginning of the char*.
When you try to use the char value with the %s specifier, it treats the value as a pointer, and tries to dereference that value. Hence, it will try to print the "string" at the memory location X, where X is the value of the char (i.e. a value from 0 to 255). This gives you an access violation/segmentation fault (the error you see at runtime).
The best workarounds for this, as noted by Cătălin Pitiș and RBerteig, are to either:
pass another parameter to specify the length of the array
add an additional null at the end of the array.

if you don't want to keep and pass around array size::
int myFunc(char **);
main()
{
char *a[2]={"Do","While", NULL};
myFunc(a);
}
int myFunc(char **P)
{
if( !P )
return 0;
while(*P != NULL)
{
printf("%s",*P);
P++;
}
}

Wrong Answer: I think you may have to dereference P when you print it, although I could be wrong.
EDIT: I'm tired, it's 3 am here but I don't feel like sleeping so I'm here trying to answer questions. After reading the criticism, I reread the question and noticed that he does dereference P, but as is stated in another answer, it's dereferenced too much. When one wants to print a char string, one wants to pass a pointer as the char string is really an array.
Another EDIT: I would also like to point out that the person who asked the question made an edit after I answered and that when I first answered it didn't read "printf("%s",**P);" it read "printf("%s", P);" and the last part was bold.

Related

How to pass a 1D array of 500 pointers to a function in C

The programm is compiling ok but once the user inputs something to the array it crashes. Any help will be appreciated :)
#include <stdio.h>
#include <stdlib.h>
void Register(char *arr[],char arr2[]);
int main() {
char *Username[500];
char table1[20];
Register(Username,table1);
return 0;
}
void Register(char *Username[],char table1[]){
int i;
for(i = 0; i < 500; i++){
scanf("%s",&table1);
Username[i] = table1;
printf("for i = %d username[%d] is %s\n\n",i,i,Username[i]);
}
}
The problem is that when you pass your arrays they decay to pointers to their first element. For "array" arguments something like e.g. char table1[] is actually char *table1. And this is a problem when you try to use the address-of operator & in scanf.
When you use &table1 in the scanf call you get a pointer to the pointer, which has the type char **, not the expected char *. This mismatch between the format %s and the expected type leads to undefined behavior and probably your crash.
The solution to this crash is to never use the address-of operator for reading strings (with e.g. the %s format), as it's even wrong when you have an actual array:
scanf("%s",table1);
As for the problem of making all elements of Username point to the single string in table1, I recommend that you use arrays of arrays for Username instead:
char Username[500][20];
This array decays to a pointer to an array, with the type of char (*)[20], which needs to be part of the Register function declaration:
void Register(char (*Username)[20]);
Then you can use this directly in the call to scanf:
scanf("%19s", Username[i]);
Also note how I limited the length of the input string, so you can't read more than the arrays can handle (and it's 19 because the array need to fit the string null-terminator as well).
In this statement
scanf("%s",&table1);
instead of reading a string into the array pointed to by the pointer table1 the string is read into the pointer itself.
You have to write
scanf("%s",table1);
Also the function Register does not make great sense because all elements of the array Username will point to the first character of the array table1. That is all elements of the array will point to the first character of the last string that was read.
You need to allocate memory dynamically. Also the second parameter of the function is redundant.
The function cam look the following way
size_t Register( char *Username[], size_t n )
{
char record[20];
int i = 0;
for ( ; i < n && scanf( "%19s", record ) == 1; i++ )
{
Username[i] = malloc( strlen( record ) + 1 );
strcpy( Username[i], record );
printf( "for i = %zu username[%zu] is %s\n\n", i, i, Username[i] );
}
return i;
}
And in main the function can be called like
size_t n = Register( Username, 500 );
\Of course you will need to free all allocated memory.

How to get a string from a function which has a void pointer?

When I try to get a string from a function which has type void*, I only get the first character.
I tried to copy string manually without using strcpy() it gives me same problem
struct arr {
int first
int last.
void **val;
};
//I have a function which is called
void *inspect_arr(const arr *ar, int position)
{
....
return ar->val[offset];
}
//I want to inspect the array so that I can compare the strings
int main()
{
char *str = calloc(10,sizeof(char));
char *k = *(char*)inspect_arr(...) //I have a string in the array
// strcpy(str,k); Doesn't work
strcmp(str,k); Invalid read from valgrind
//If array has an integer type then I would write my code like this:
//int a = *(int*)inspect_arr(...) but I can not do the same thing for char
}
I get Segmentation fault when I run the program.
One problem is that first * in *(char*)inspect_arr(...).
There you dereference the pointer, getting only the first character. It's equivalent to ((char*)inspect_arr(...))[0].
To make it more troublesome, you then assign this single character to the pointer k. This doesn't make k point to the character, it make k point to whatever address corresponds to that characters encoded value. With e.g. ASCII and the character 'd' the initialization is equivalent to
char *k = 100;

char* or char ?. I don't understand about the declaration here

I wrote a function that cuts all the left space of an inputted string. These two functions give the same output "haha" when input is " haha".
My question are:
1) Why the 1st one need return but the 2nd one doesn't. I added "return s" and it made a syntax error.
2) Are there any different in these if I use it in another situation?
3) Many said that 2nd one return a character not a string, how about my output ?
char *LTrim(char s[])
{
int i=0;
while(s[i]==' ')i++;
if (i>0) strcpy(&s[0],&s[i]);
return s;
}
and
char LTrim(char s[])
{
int i=0;
while(s[i]==' ')i++;
if (i>0) strcpy(&s[0],&s[i]);
}
This is my main():
int main()
{
char s[100];
printf("input string ");
gets(s);
LTrim(s);
puts(s);
return 0;
}
Your second code segment doesn't seem to have a return statement, please correct that for getting the correct answer.
The first function is returning a character pointer, which will be memory pointing to the starting location of your character array s, whereas the second function is returning a single character.
What you do with the values returned is what will make the difference, both the codes seem to be performing the same operation on the character array(string) passed to them, so if you are only looking at the initial and final string, it will be same.
On the other hand, if you actually use the returned value for some purpose, then you will get a different result for both functions.
char *LTrim(char s[]){} is a function of character array / string which returns character pointer i.e. returns reference / memory address.
While char LTrim(char s[]) is a function of character array / string, which return character only.
char is a single character.
char * is a pointer to a char.
char * are mostly used to point to the first character of a string (like sin your example).
In the first example you return your modified svariable, and in the second you return nothing so it's best to change the return value to void instead of char.

what does, "passing argument 2 of 'strstr' makes pointer from integer without a cast," mean in C

I'm trying to have a list of cheeses that you can search through to get to a certain one. When I am done I also want to add info about each one. But every time I run my code I get the error shown in the title. Here is my code:
#include<stdio.h>
#include<string.h>
int main()
{
char cheeses[][20] = {
"Cheddar",
"White Cheddar",
"Colby Jack",
"Gouda",
"Blue Cheese",
"Gorgonzola",
"Asiago",
"Limburger",
"Feta",
"Brie",
};
void find_cheese(char search_for)
{
int i;
for (i = 0; i < 5; i++) {
if (strstr(cheeses[i], search_for))
printf("Cheese %i: '%s'\n", i, cheeses[i]);
}
}
int main()
{
char search_for[20];
printf("Search for: ");
fgets(search_for, 20, stdin);
find_cheese(search_for);
return 0;
}
}
Why is this happening? I've looked it up in my book, but can't seem to find the answer.
The second argument to strstr should be const char*. You're passing a single char.
strstr expects a pointer to char as the second argument:
const char * strstr ( const char * str1, const char * str2 );
while you are passing a char.
void find_cheese(char search_for)
should be
void find_cheese(char *search_for)
because it is looking for a string (char *), not a single character.
strstr() takes a string (char *) as the second argument.
For usage see here.
The problem in your code is you're accepting the passed the array incorrectly:
void find_cheese(char search_for) //This line is wrong
{
What you wanted to do was:
void find_cheese(char search_for[])
EDIT:
Here's what is happening. When you access the array in your main function:
find_cheese(search_for);
What you're actually doing here is passing an address. (When you just access the array search_for you get an address). So when your prototype said it was taking a char the compiler saw the address (4 bytes, looking like an int) and truncated it to fit in a one byte char.
The way you prevent that is by passing the whole "string" (a string in C is a character array). So you can do this by passing search_for as an array, or as a pointer (address to a character array).
void find_cheese(char search_for[])
and
void find_cheese(char *search_for)
Will both work and are equivalent for your needs (passing to strstr())

What is the size of a double pointer string?

Assume I have char **argv. How do I determine its size?
I have a string - an example would be: sleep 30 & that is held in argv. I would like to be able to access the last array in *argv. In this case, the last array contains &. How can I access it? strlen(argv) doesn't seem to work properly. sizeof() obviously wouldn't work properly because **argv is a pointer.
Note: I am not talking about **argv as an argument in main(), therefore, I do not have argc or any other indicator of how long the string is.
EDIT: Edited to work with a custom array of strings. A NULL pointer indicates the end of the array. Although this declares an array of 4 strings, this method could be used with a dynamically sized array.
#include <stdio.h>
int main()
{
char* custom[4] = { "sleep", "30", "&", NULL };
int last;
for (last = 0; custom[last + 1]; last++);
printf("%i - %s\n", last, custom[last]);
return 0;
}
// ./a.out
// > 2 - &
For this to work for you, you would have to edit your program to explicitly include an extra NULL string in your char** when you build it. Without that indicator, the address after the last string wouldn't necessarily be NULL, so you could include garbage in the count or cause a segmentation fault.
Passing in a count like argc is the most common usage - but you say you don't have that.
Then the usual way is to have the last element of argv to point to NULL to indicate it is the last array element.
int argc = 0;
while (*argv++) {
argc++;
}
You may need to use strtok to tokenize the arguments and work through them until you have the last one.
Referemce for strtok.
char *argv[] = {"abc","123","xya"};
//prints the last string
printf("%s",a[strlen(*a)-1]);
// if you are sure that the array of strings ends with NULL
char *temp = 0 ;
while(*argv){
temp = *argv;
(*argv)++;
}
//temp has the last string

Resources