I am new to programming and C in general and the last few weeks I try to get the concept of pointers, arrays and how they are connected.
At the moment I experiment with command line arguments in C and I read here on this platform that argv can be syntactically defined differently, however the semantic stays the same.
int main(int argc, char *argv[])
is equal to
int main(int argc, char **argv)
Okay, but why is my code behaving differently when I try to initialize an array in these ways:
char *s[] = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get as output as expected: o and 3.
But when I initialize the array like
char **s = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get a segmentation fault or other errors which I cannot understand like (near initialization for āsā)
I guess you cannot initialize an pointer to a pointer array with 2 asterisks.
Maybe someone can provide me with more information about these relation and how these 2 definitions differ from each other.
They are completely different:
char *s[]
is an array of pointers. Arrays cannot be assigned or used as values
This code will not compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
a++;
}
void bar(void)
{
a1 = a;
}
char **s
is a pointer to a pointer and can be assigned or used as an lvalue.
This code will compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
s++;
}
void bar(void)
{
s1 = s;
}
https://godbolt.org/z/vqxv913WY
Related
I have an array of n strings where n is not known at compilation time.
The real input is a giant string that I will splice, and add the parts to each position of the array.
In the example I've simulated a sentence with n=3 , but n can be any number.
void addWords(char *array[][300], int n) {
char p[] = "Hello ";
char p1[] = "World ";
char p2[] = "!";
strcpy(array[0],p);
strcpy(array[1],p1);
strcpy(array[2],p2);
printf("%s%s%s\n",array[0],array[1],array[2]);
}
int main(int argc, char const *argv[])
{
int n = 3;
char array[n][300];
addWords(array,3);
return 0;
}
The code gives segmentation fault and I cannot identify the cause.
//void addWords(char *array[][300], int n) {
void addWords(char array[][300], int n) { // <== use `char array[][300]`
char p[] = "Hello ";
char p1[] = "World ";
char p2[] = "!";
strcpy(array[0],p);
strcpy(array[1],p1);
strcpy(array[2],p2);
//printf("%s%s%s\n",p[0],p[1],p[2]);
printf("%s%s%s\n",array[0],array[1],array[2]); // <== I think you meant `array` instead of `p`
}
This
void addWords(char *array[][300],
^^^^^^^^^^^^^^^^^^
means
pass a pointer to an array containing 300 char pointers
What you want to say is
pass a pointer to an array containing 300 char
So all you need is:
void addWords(char *array[][300], --> void addWords(char array[][300],
I see that you declared 'addWords' with argument of type "char *array[][300]", but pass value of type "char array[n][300]". Different types.
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.
#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.
I'm trying to swap two char with two table pointers.
Can someone explain to me what's wrong in my code?
The terminal says char** is expected but I don't know what to do, so I think I don't really understand how pointers work for tables.
void echangeM2(char **ptab1, char **ptab2){
char *tmp = *ptab1;
*ptab1 = *ptab2;
*ptab2 = *tmp;
printf("%s\t %s",*ptab1,*ptab2);
return;
}
int main(void) {
char tab1[25];
char tab2[25];
char *adtab1;
char *adtab2;
*adtab1 = &tab1;
*adtab2=&tab2;
printf("type two words");
scanf("%s %s",tab1,tab2);
echangeM2(adtab1,adtab2);
return 0;
}
The following code should work for you:
#include <stdio.h>
void exchangeM2(char* *ptab1, char* *ptab2) { // accepts pointer to char*
char* tmp = *ptab1; // ptab1's "pointed to" is assigned to tmp
*ptab1 = *ptab2; // move ptab2's "pointed to" to ptab1
*ptab2 = tmp; // now move tmp to ptab2
printf("%s\t %s",*ptab1,*ptab2);
}
int main(void) {
char tab1[25];
char tab2[25];
char* adtab1;
char* adtab2;
adtab1 = tab1; // array name itself can be used as pointer
adtab2 = tab2;
printf("type two words");
scanf("%s %s",tab1,tab2);
exchangeM2(&adtab1, &adtab2); // pass the address of the pointers to the function
}
echangeM2(&adtab1,&adtab2);
This should fix the compile errors. You are passing char* pointers to a function that expects a char ** pointer
Edit: Actually looks like you want something like
char **adtab1;
char **adtab2;
adtab1 = &tab1;
adtab2=&tab2;
...
echangeM2(adtab1,adtab2);
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.