I've read several discussions of passing char * in C.
stackoverflow: passing-an-array-of-strings-as-parameter-to-a-function-in-c
stackoverflow: how-does-an-array-of-pointers-to-pointers-work
stackoverflow: whats-your-favorite-programmer-ignorance-pet-peeve
drexel.edu: Character arrays
Many of them include discussions of arrays, but I want to stay away from that.
I'm writing a sample program to teach myself about the passing of char * and char ** in C. This is an exercise in passing char *, without using (pointers to) arrays. Also no concerns for execution efficiency. :-)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void get_args_works(int, char **, char **);
void get_args_broken(int, char **, char *);
char *get_string(int, char **);
int main(int argc, char **argv)
{
char *string_works;
char *string_broken;
get_args_works(argc, argv, &string_works);
get_args_broken(argc, argv, string_broken);
printf("in main string_works (%p) = %s\n",string_works,string_works);
free(string_works);
printf("in main string_broken (%p) = %s\n",string_broken,string_broken);
free(string_broken);
}
void get_args_works(int argc, char **argv, char **string)
{
*string = get_string(argc, argv);
printf("in get_args_works %p string %s\n",*string,*string);
}
void get_args_broken(int argc, char **argv, char *string)
{
string = get_string(argc, argv);
printf("in get_args_broken %p string %s\n",string,string);
}
char * get_string(int argc, char **argv)
{
int i;
char *string;
string = malloc(40);
// placeholder in case -s switch not found below
strcpy(string,"-s switch not found below");
for(i = 0; i < argc; i++)
{
if(argv[i][0] == '-')
{
switch(argv[i][1])
{
case 's':
// release above malloc(40) for "-s switch not found below"
free(string);
// make room for storing variable
string = malloc(strlen(argv[++i]) + 1);
// the argv just after -s
strcpy (string,argv[i]);
break;
}
}
}
return string;
}
You can also view the same code on github
The above code is somewhat self documenting. main() declares two char * variables, and passes them as parameters to their respective get_args() functions.
Each get_args() function calls char * get_string(int, char **), using the exact same call (but different way to collect the return value).
get_string() works fine; it does a malloc() and returns the pointer back to the calling function. That code works, and each get_args() function receives the return value as I expect.
But then, when the get_args() functions return to main(), why does the dereferenced pointer value get back to main (from get_args_works(), but not the pointer's value (from get_args_broken())?
(i.e. I can see that if I dereference the pointer (&string_works) when sending as a parameter, it works. But why? Isn't char * string_broken already a pointer? Why does it need the "extra" dereference when sending as a parameter?)
I'm hoping for a winning answer that explains how you (yes, you) conceptualize sending char * as a parameter vs receiving it as the function's return value.
int get_args_broken(int argc, char **argv, char *string)
{
string = get_string(argc, argv);
printf("in get_args_broken %p string %s\n",string,string);
}
You're only modifying the string local (automatic) variable. That's not visible to the caller in any way. Note that this means you're freeing a wild pointer in main.
It's wrong for the same reason:
int get_sum(int sum, int a, int b)
{
sum = a + b;
}
is; the parameter is copied by value. Also, you're not returning an int (as you declared you would).
int get_args_works(int argc, char **argv, char **string)
{
*string = get_string(argc, argv);
printf("in get_args_works %p string %s\n",*string,*string);
}
is correct (except the missing return). You're not modifying string, which would be pointless. You're modifying the object at the location in string, which in this case is a char *.
EDIT: You would need to triple * the argv if there was a function calling main, and you wanted to set that function's variable to a different char **. E.G.
void trip_main(int *argc, char ***argv)
{
*argc = 10;
*argv = malloc(*argc * sizeof(char *));
}
void caller()
{
char **argv;
int argc;
trip_main(&argc, &argv);
}
One of the needs to use Pointer to a pointer (here get_args_works()) is to modify (or return) more than on variable from a function, as in C it's not possible to return more than one variable.
get_args_works() works 'coz, you are passing pointer to a pointer & a reference to it is there in your main().
But in get_args_broken() you are passing just a pointer. Nothing wrong here, now you do malloc() & return back the memory allocated string to get_args_broken(), still nothing wrong here. But now, this mem allocated string is local & main() does not have a reference to this var. So when you dereference char *string_broken; in main() it might cause undefined behavior.
Hope this's clear.
Related
I have the following code from previous exam in c:
int main(int argc, char **argv) {
char s[] = "123";
int* a = (int*) s;
printf(("%x"),*a);
return 0;
}
The output is: 333231
My question is why? how does changing the pointer effect it?
You don't have to declare a separate variable. This would do:
printf(("%x"),(int*)s);
The pointer type dictates how the pointee is interpreted when the pointer is dereferenced.
I wanted to make a simple str_join function in C (to learn a bit more about pointers and arrays), which literally joins two string together.
#include <stdio.h>
#include <stdlib.h>
int str_size(char *str);
void str_join(char *str1, char *str2);
int main(int argc, char **argv)
{
char *part1 = "Hello ";
char *part2 = "World!";
str_join(part1, part2);
printf("%s\n", part1);
return 0;
}
int str_size(char *str)
{
char c;
for(int i = 0;; i++)
{
c = str[i];
if(c == '\0')
return i + 1;
}
}
void str_join(char *str1, char *str2)
{
int str_size_1 = str_size(str1) - 1; //Last char is '\0', don't need them 2 times
int str_size_2 = str_size(str2);
char str3[str_size_1 + str_size_2];
int i;
for(i = 0; i < str_size_1; i++)
str3[i] = str1[i];
for(i = 0; i < str_size_2; i++)
str3[i + str_size_1] = str2[i];
str1 = (char *)str3;
}
It looks simple (maybe too simple).
I excepted the output to be:
Hello World
but it looks like:
Hello
I compiled the program using following command:
gcc main.c -o main
And ran it:
./main
I don't see my failure, could someone point me to my error?
Thank you for helping me out!
In C, function arguments are passed by value. Any changes made to any parameter from inside the function is will not reflect to the caller (actual argument).
So, in your case, str1 = (char *)str3;, does not do what you think it does.
That said, wait, stop!! str3 is a VLA and lifetime is the block scope. You cannot possibly return the address of the first element and expect that to be valid outside the scope for accessing the memory location(s). You need to allocate memory in such a way that it outlives its scope., You have to either
use an array with static storage (cannot be combined with VLAs)
use memory allocator function
You are not returning the pointer you think you are returning from the function.
str1 = (char *)str3;
You seem to assume that this changes str1 so that it points to the (correctly) joined string str3, but this change is not visible outside of the function.
You can fix this in (at least) two ways:
1) Allocate with malloc
char *str3 = malloc(str_size_1 + str_size_2);
And then return this pointer from the function (instead of void)
or 2)
pass a pointer to the pointer to the function, like this
void str_join(char **str1, char *str2)
And then
*str1 = str3;
The objective you wish to achieve is done with the help of call by reference method of the function calling method. But in your code, the str_join is a call by value function. When you change the value of str1 it is changed just for the scope of the function. As, soon as you come out of the str_join scope the value of str1 is again changed to the earlier one, becuase what you are passing to the function is not the address of str1 but a copy of the value of str1. You should try this instead :
void str_join(char **str1, char **str2)
// though the str2 need not to be passed by reference you can leave it as it is now
Replace the str1 inside the function with *str1
Then you can call it in your main function as : str_join(&str1, &str2)
The & sign signifies that you are passing the address of str1 and str2
I'm sure that there are many ways of implementing what is required here. A reasonably idiomatic way in C would be to create a new dynamically-allocated string large enough to hold both the original strings, and return that to the caller.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
char *str_join(char *str1, char *str2)
{
char *result = malloc (strlen (str1) + strlen (str2) + 1);
strcpy (result, str1);
strcat (result, str2);
return result;
}
int main(int argc, char **argv)
{
char *part1 = "Hello ";
char *part2 = "World!";
char *joined = str_join(part1, part2);
printf("%s\n", joined);
free (joined);
return 0;
}
The caller will have to call free() on the result. It's reasonable common practice to assume that any function that returns a "char *" is returning something that has to be freed, whilst a function that returns a "const char *" is returning something that doesn't need to be freed. A number of basic, long-standing functions in the C standard library don't follow this convention, however.
I am using a function to parse through userID, and paswd and some error checking. The function is called from my main()... However when executed only the first 4 characters of my UserID and Pswd are successfully extracted. I am new to C-programming and coming from C# I am not sure where I am going wrong. This should be fairly easy, can someone point me in the right direction?
static void func1(int argc, char *argv[], char *UserID[30], char *Psw[30])
{
strncpy(UserID, argv[1], sizeof(UserID));
strncpy(Psw, argv[2], sizeof(Psw));
}
int main(int argc, char *argv[])
{
char UserID[30];
char Psw[30];
func1(argc, argv, UserID, Psw);
}
Also, just to point out, if I don't use the external function, and have all the code in my main func then it works.
EDIT:-
Figured out the issue:-
static void func1(int argc, char *argv[], char *UserID, char *Psw)
{
strncpy(UserID, argv[1], UserIDMaxSize);
strncpy(Psw, argv[2], PswMaxSize);
}
int main(int argc, char *argv[])
{
char UserID[UserIDMaxSize + 1]; /* max val defined in a header file */
char Psw[PswMaxSize + 1]; /* max val defined in a header file */
func1(argc, argv, UserID, Psw);
}
sizeof doesnt work quite as I expected it to.. it was reading the size of my pointer which is always 4 chars by default.
I guess your pointer has a size of 4 Byte. therefore you only read 4 chars.
Pass the array size to the function
static void func1(int argc, char *argv[], char *UserID, size_t UserIDSize,
char *Psw, size_t PswSize)
{
if (argc> 1) strncpy(UserID, argv[1], UserIDSize);
if (argc> 2) strncpy(Psw, argv[2], PswSize);
}
int main(int argc, char *argv[])
{
char UserID[30] = {0};
char Psw[30] = {0};
func1(argc, argv, UserID, sizeof UserID, Psw, sizeof Psw);
}
To insure the destination arrays are null character terminated, suggest strncat() --> "A terminating null character is always appended to the result." strncpy() has too many problems, it does not always result in an array with a null character.
static void func1(int argc, char *argv[], char *UserID, size_t UserIDSize,
char *Psw, size_t PswSize) {
UserId[0] = '\0';
// if (argc> 1) strncat(UserID, argv[1], UserIDSize);
if (argc> 1) strncat(UserID, argv[1], UserIDSize - 1);
Psw[0] = '\0';
// if (argc> 2) strncat(Psw, argv[2], PswSize);
if (argc> 2) strncat(Psw, argv[2], PswSize - 1);
}
[Edit]
Corrected code - off by 1
TL;DR
The sizeof isn't doing what you're expecting. Try using strlen instead.
You're only getting 4 characters copied because sizeof(char*[N]) for any N is just going to be the size of a pointer. On your platform, a pointer must be 4 bytes (32 bits).
I think you actually mean to pass the base-address of the array into the function, but in that case your types aren't quite right. Your compiler should be warning you about this. You should remove the * from your last 2 argument types:
static void func1(int argc, char *argv[], char UserID[30], char Psw[30])
That should get rid of the warning, and it should actually make sizeof behave correctly as well (since sizeof(char[30]) is 30). However, it's very easy to make mistakes with sizeof since the behavior with a char* and char[] are different... I'd prefer using strlen (or strnlen if you want to avoid possible buffer overflows) here instead, which will simply tell you how many non-null characters you have.
Using strnlen rather than sizeof would also help to tip you off that your parameter types are wrong, since it will complain that you're trying to pass a char** to a function that expects a char*.
Solution
#include <stdio.h>
#include <string.h>
void func1(int argc, char *argv[], char *UserID, char *Psw)
{
strncpy(UserID, argv[1], strlen(argv[1]));
strncpy(Psw, argv[2], strlen(argv[2]));
printf("DATA: %s \n",UserID);
printf("DATA1: %s \n",Psw);
}
int main(int argc, char *argv[])
{
char UserID[30];
char Psw[30];
printf("argv1 %ld \n",strlen(argv[1]));
printf("argv2 %ld \n",strlen(argv[2]));
func1(argc, argv, UserID, Psw);
}
I need to store the memory address of a string in an int pointer out parameter. I've created the code below to test the implementation.
void getMemAddress (int *a) {
char str[80] = "Hello world";
a = (int*)&str; // Assign memory address of str to a
printf("%s", (char*)a);
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(memaddress);
printf("%s", (char*)memaddress);
return 0;
}
printf("%s", (char*)a);
prints "Hello World" as it should but
printf("%s", (char*)memaddress);
prints null
How could I go about retrieving the actual memory address as using it to access the original string?
Thanks!
Parameters are passed by value in C. Similar issues have been answered countless times on stackoverflow.
You need this:
void getMemAddress (int **a) {
char str[80] = "Hello world";
*a = (int*)str; // Assign memory address of str to *a
printf("%s", (char*)*a);
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(&memaddress);
printf("%s", memaddress);
return 0;
}
Casting a memory address to int won't work on a 64 bit system. On a 32 bit system it works, but it's not very clean.
Other problem. You are returning the address of a local variable that is on the stack. As soon as you leave the getMemAddress function the str buffer will be overwritten by following function calls (also a classic problem). Never return the address of a local variable.
You are assining the address of &str to your function-local copy of the pointer a. What you need is to modify getMemAddress so that it takes int **a as an argument, and assign it like this:
*a = (int *) str;
then in main:
int *memaddress;
getMemAddress(&memaddress);
And one more thing-- str only exists inside your function. Once you exit the function, you won't be able to access it. To fix this, make str a char pointer and use malloc to allocate some memory for it. Then use strcpy to insert your string.
To modify something in a function, you need to pass a pointer to the thing you want to modify.
In this case you want to modify a pointer, so you need to pass a pointer to the pointer.
void getMemAddress (int **a) { // <-------------- added a *
char str[80] = "Hello world";
*a = (int*)str; // <-------------- added a *
printf("%s", (char*)*a); // <-------------- added a *
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(&memaddress); // <-------------- added a &
printf("%s", (char*)memaddress);
return 0;
}
Also, &str should be &str[0] or just str.
Also, str is a local variable, so it will cease to exist once getMemAddress returns (and then the printf call in main will probably print garbage). You could make str static, or you could return a pointer to a string literal instead (char *str = "Hello world"; *a = (int*)str;).
#include<stdio.h>
void display(int n, char *str[])
{
int i=0;
while(i<n) printf("%s ",str[i++]);
}
int main()
{
display(1,"Hello");return 0;
}
when I run this above code I get warnings as
arr.c: In function 'main':
arr.c:11:12: warning: passing argument 2 of 'display' from incompatible pointer
type
display(1,"hello");
^
arr.c:3:6: note: expected 'char **' but argument is of type 'char *'
void display(int n,char *str[])
But then how is it different from
int main(int argc, char * argv[])
And what is the difference between
char **argv and char *argv[]
I am strictly not asking about something like char *argv[100]
As a parameter of a function both char **ptr and char *ptr[] are equivalent, otherwise they are different. Former is a pointer to pointer to a char while latter is an array of pointers to char.
When a string literal is passed to a function, then pointer to its first character (char * type) is passed. You need to change the function's second parameter to char *str.
void display(int n, char *str)
{
// Function body
}
Well, char **ptr is a double pointer (pointer to a pointer) of char while char *ptr[] is an open array of pointer to char.
According to cdel, char **p; gives the result of "declare p as pointer to pointer to char" while char *p[]; gives "declare p as array of pointer to char."
Character strings are always arrays, and arrays are generally always pointers, so the two are generally equivalent which means that **ptr = *ptr[]. What you end up with is an array of an array of chars, or an array of strings. Take main() for instance:
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "some string") == 0) do something;
}
Do some stuff;
return(0);
}
Another way to declare it is
int main(int argc, char *argv[])
Programmatically, it's easier to understand *ptr[] than **ptr.