I have this small program:
#include <stdio.h>
int main() {
char *argv[3] = {{"abc"}, {"def"}, {"ghi"}};
printf("%c\n", (*++argv)[1]); //error. I wanted to print 'b'
printf("%c\n", *++argv[1]); //prints e
return 0;
}
The error message:
error: cannot increment value of type 'char *[3]'
printf("%c\n", (*++argv)[1]);
I want to increment argv to point to b. I took this usage (*++argv)[i] straight from C Programming Language by K&R where they have an example on page 117 on incrementing argv exactly like I did. They also point out that (*++argv)[0] is the pointer to the first character in a string while *++argv[0] increments the pointer argv[0]. Indeed (*argv)[1] will print b while *argv[1] will print d. Yet somehow incrementing (*++argv)[0] just keep resulting in error.
First, this:
char *argv[3] = {{"abc"},{"def"},{"ghi"}};
Should be this, as noted by others:
char *argv[3] = {"abc", "def", "ghi"};
Second, what you've done is not what the K&R book does.
Array names act like they were constant pointers, so you can't change them like you tried to with that argv = argv + 1 (expanded version of ++argv).
But the book does that to an argv passed into main by the command line, so when char* argv[] enters main, it decays to a pointer to pointer (char**) and then, yes, you could make (*++argv)[1] work if you pass the strings as command line arguments.
Try to create a bogus argv inside main, like you did, and compare its related addresses with the addresses related to a real argv passed into main via command line.
You'll see that one is a char** and the other is a char* array:
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("argv: %p\n", argv);
printf("&argv[0]: %p\n", &argv[0]);
printf("&argv: %p\n\n", &argv);
char* bogus_argv[] = {"abc", "def", "ghi"};
printf("bogus_argv: %p\n", bogus_argv);
printf("&bogus_argv[0]: %p\n", &bogus_argv[0]);
printf("&bogus_argv: %p\n\n", &bogus_argv);
printf("%c\n", (*++argv)[1]); // prints 'b'
printf("%c\n", *++argv[1]); // prints 'e'
return 0;
}
Run: ./program abc def ghi
Output on my machine:
argv: 0x7ffcde5aca98
&argv[0]: 0x7ffcde5aca98
&argv: 0x7ffcde5ac9a0
bogus_argv: 0x7ffcde5ac980
&bogus_argv[0]: 0x7ffcde5ac980
&bogus_argv: 0x7ffcde5ac980
b
e
The example from K&R refers to argv as defined as the second argument to function main. Your definition is different, you define an array of 3 pointers to strings whereas the function argument is a pointer to such an array.
The function prototype syntax is somewhat misleading as the same syntax is used for a different type of object. Some people prefer this syntax:
int main(int argc, char **argv) {
...
}
With this prototype, the nature of argv (a pointer to a pointer to char) appears more explicitly, but many programmers prefer the equivalent char *argv[] syntax to underline the fact that argv points to an array of pointers as opposed to a single pointer.
argv being an array in your code, you cannot increment it: this explains why you get an error for printf("%c\n", (*++argv)[1]);.
You can change your program this way:
#include <stdio.h>
int main(void) {
char *argument_array[4] = { "abc", "def", "ghi", NULL };
char **argv = argument_array;
printf("%c\n", (*++argv)[1]); // will print 'e' instead of 'b'
printf("%c\n", *++argv[1]); // prints 'h', not 'e'
return 0;
}
Also note that you should remove the redundant {} in the initializer, and the ++ operator is prefix, so the output is not exactly what you expect.
you made a mistake with array your declaration. It should you a warning. It should be
char *argv[3] = {"abc","def","ghi"};
The inner braces are not neccessary as strings are char pointers and therefore "arrays".
You could declare a second pointer variable and assign it to argv:
char ** p;
p = argv;
and then increment p.
Last but not least, if you want to print b first and then e, you have to put the "++" operator behind the variable. Otherwise it would increment the pointer before the evaluation and you would print e and h.
Related
I have been messing a bit with C lately and i have come across some "weird" behavior
#include <stdio.h>
int main(int argc, char **argv) {
printf("&argv=%d\n&argv[0]=%d\n", &argv, &(argv[0]));
return 0;
}
the pointer to argv is completely different from the pointer of argv[0]
as C arrays are contiguous shouldn't the pointer to the argv be the same to the start of the first C string?
in my head the argv should look something like this
char **argv = {char *, char *, char *};
where the start of the argv array be the same as the start of the first string
how is this structured and why aren't the two pointers the same?
printf requires that you use the format specifier that matches with the type of the argument that you pass. %d does not match with the type of the arguments that you pass (it requires int or similar), and therefore the behaviour of the program is undefined.
I recommend avoiding printf in general (Edit: question used to be tagged [c++]), but if you must use it, then you can use %p format specifier for void*. You must convert the pointer arguments to void*.
Once you've fixed the program, you'll find that the addresses are indeed different. The explanation is that argv is a pointer that doesn't point to itself. Hence its value is different from where it is stored. It points to another object stored elsewhere.
... the argv array ...
argv is not an array. Function parameters cannot be arrays. argv is a pointer.
You can create an analogous structure like this:
char args[] = "./a.out\0example\0argument";
char* ptrs[] = {
args + 0,
args + 8,
args + 16,
0,
};
int argc = 3;
char** argv = ptrs;
// argv == &ptrs[0]
// argv != &argv
C arrays are contiguous, but on the one hand you took the address of the array, and on the other hand you took the addresses in the array.
This is perhaps more obvious if you print out the argv[i] values for all values of i like this:
$ cat pointer.c
#include <stdio.h>
int main(int argc, char** argv) {
int i;
for (i = 0; i < argc; ++i) {
printf("&argv=%p\targv=%p\t&argv[%d]=%p\n", &argv, argv, i, &(argv[i]));
}
return 0;
}
$ gcc pointer.c
$ ./a.out 1 2 3
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[0]=0x7ff7b37167e0
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[1]=0x7ff7b37167e8
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[2]=0x7ff7b37167f0
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[3]=0x7ff7b37167f8
While %p is a better format specifier, your %d would have worked too, if you were printing out the address of the first element of the array (which is just argv) instead of a pointer to the address of the first element of the array (which is &argv and not what you meant).
as C arrays are contiguous shouldn't the pointer to the argv be the same to the start of the first C string?
The address of an array is indeed the same as the address of its 1st element, yes. But argv is not an array, it is a pointer to an array. &argv is the address of the pointer itself, not the address of the array that it is pointing at. Evaluating argv by itself will return the address of the array. And as such, &(argv[0]) is the address of the 1st element of the array.
Try this instead, and you will see that argv and &argv are two different addresses:
printf("&argv=%p\nargv=%p\n&argv[0]=%p\n", &argv, argv, &(argv[0]));
For starters you shall use the conversion specifier %p to output pointers using the function printf.
Function parameters are local variables of the function.
You can imagine the function main the following way
int main( /*int argc, char** argv */) {
int argc = some_argument expression;
char **argv = some_argument_expression;
//...
Thus the expression &argv gives the address of the local variable argv
The expression argv[0] is the first element of the array pointed to by the local variable argv that has the type char **. And the expression &argv[0] gives the address of the first element of the pointed array.
So &argv is the address of the local variable argv that is defined in main as its parameter. While &argv[0] is the address of the first element of an array that is defined outside the function main.
To make it more clear consider a very simple program.
#include <stdio.h>
int main* void )
{
int a[] = { 1, 2, 3, 4, 5 };
int *p = a;
printf( "&p = %p, &p[0] = %p\n", ( void * )&p, ( void * )&p[0] );
}
As you see the expression &p yields the address of the variable p that occupies its own extent of memory while the expression &p[0] yields the address of the first element of the array a that occupies a separate extent of memory.
main()
{
const char **a = {"string1","string2"};
printf("%c", *a); /* prints s */
printf("%s", a); /* prints string1 */
printf("%s", a+1);/* prints ng1 */
}
GCC v4.8.3 prints "%s" for the last printf, where as http://codepad.org/ prints "ng1".
I thought that the code will create an array of pointers to two strings and the base address assigned to a, which allows normal pointer arithmetic. but it seems that there is something wrong with the assumption.The first printf suggests that my assumption is wrong. can anyone explain why this behavior is observed? ( note that VS 2012 has thrown an error saying too many initalizers where as GCC has thrown a warning for incompatible pointer assignment). I am aware of the warning due to incompatible pointer assignment.
const char **a is not an array of pointer to two strings. It declares a to be a pointer to pointer to const char.
const char **a = {"string1","string2"}; //No memory is allocated to store string literals
will invoke undefined behavior and you may get either expected or unexpected results.
To declare a as an array of two pointers you need to change the declaration as
const char *a[] = {"string1","string2"};
The memory range in your program's stack looks like this: (notice that it is not allocated before assignment which is wrong)
char** a = {s, t, r, i, n ,g, 1, \0, s, t, r, i, n, g, 2, \0}
Therefore when you print the command:
printf("%c", *a);
You are dereferencing the first character of the string which is 's'.
On the other hand, when you print the command:
printf("%s", a);
you are printing a string that starts at pointer a and finishes at '\0'. That's why you see the output 'string1'.
Lastly, when you type "a+1" you increase the pointer in one step (example here: How to increment a pointer address and pointer's value?). in this case because char** is a pointer, and every pointer is 4 byte, the "+1" jumps 4 chars forward.
Therefore when you print the command:
printf("%s", a+1);
The printf starts at the pointer 'a' + 4 bytes and ends at '\0'. That's why the output is 'ng1'.
Hope it was clear enough.
This is due to the following peculiar initialization performed by GCC.
please see int q = {1,2}; peculiar initialization list. the statement const char **a = {"string1","string2"}; results in a being treated as if const char **a = "string1". this solves the mystery as *a would print 's', a would print string1.
This should copy a string but prints garbled results. Can anyone help me out?
int main () {
const char *a = "Hello\n";
const char *b = "World\n";
strncpy(&b, &a, strlen(a));
printf("%s %s", a, b);
return 0;
}
I expect "Hello Hello" but the terminal prints:
\
Hello
GCC prints an warning about a and b having incompatible pointer types even though strncpy's signature:
char * strncpy(char *s1, const char *s2, size_t n)
asks for 2 char pointers. Is that because arrays are always char** as mentioned in https://stackoverflow.com/a/20213168 ?
You are passing char ** twice where char* is expected.
&b takes the address of b, with b being a char*, the address of a char. So &b is char **. The same issue appears for a.
Update:
Just saw b isn't an array but a pointer which points to a "string"-literal. The latter are constant, you cannot change them, so copying to a literal's address (what the code actually does not, because of the misplaced &-operator in frot of the b) has to fail.
To get around this define b like this
char b [] = "World\n";
Is that because arrays are always char** [...]
Arrays aren't "always char **".
If an array is passed as argument to a function it decays to a pointer to it's first element. So
char b[] = "test";
would decay to a
char * pb
with pb pointing to the char 't', the first characters of `"test".
Two problems:
You should not copy into a buffer pointed by const char *, as it is a constant buffer.
The arguments for strncpy are char *s, but you passed char **, thus overwriting the pointers themselves, not the content they point to.
Compile your code with -Wall to see warnings that will tell you how to fix this.
Two issues:
1) You should use strncpy(a, b, strlen(a)), if a is a char* and b a const char*. The compiler error you're getting alludes to this.
2) You have undefined behaviour. You've allocated const char* string literals. A compiler may put them in read-only memory. And an attempt to modify either of them is not allowed: even a single element change could cause a program crash.
One remedy would be to use char* b = malloc(/*ToDo - your size here*/);. Remember to free the memory once you're done with it.
I'm trying to learn C now, I'm coming from Java and there is some stuff that is new to me.
I want to print a string and send an int and a string(char array) to another method. But I keep getting some errors that I don't know how to fix.
Would really appreciate if someone could take their time and explain to me what's wrong in my code. I'm quite disoriented at the moment with these pointers. When to use %s and %c when printing etc...
Code:
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
string = "hello!";
int *ptr;
sptr = &string;
ptr = &k;
printf("%s \n", &sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}
And the errors.
test.c: In function ‘main’:
test.c:8:9: warning: assignment makes integer from pointer without a cast
test.c:15:2: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char **’
tezt.c: In function ‘sendptr’:
tezt.c:8:8: error: incompatible types when assigning to type ‘char[6]’ from type ‘char’
Thanks for your time! :)
First functions solved.
Second function i get this..
tezt.c: In function ‘sendptr’:
tezt.c:5:2: error: invalid initializer
#include <stdio.h>
void sendptr(int *test, char *fname)
{
char fnamn[] = &fname;
int pt;
pt = *test;
printf("%p \n", test);
printf("%d \n", pt);
printf("%s \n", fnamn);
}
char string;
string = "hello!";
First problem: you're declaring string as a single char, not as an array. Also, you can only initialize the array to a string literal in a single statement.
char string[] = "hello!";
Second problem: sptr is a pointer-to-char, so it has to point to the first element of your string. Either of these will do:
char *sptr = string;
char *sptr = &string[0];
Then, when printing the string, just pass sptr directly.
printf("%s \n", sptr);
EDIT for your next question.
char fnamn[] = &fname;
You're trying to assign a char** (pointer to pointer to char) to an array. That just won't work. If you want to copy the string pointed to by fname into fnamn then you need to use a function such as strncpy.
char fnamn[MAX_STRING_SIZE];
strncpy(fnamn, fname, MAX_STRING_SIZE);
Having said that, if you just want to print the string, then print fname directly without copying it into your array first.
Here's a corrected version of the program with some annotation:
#include <stdio.h>
int main(void) // int and (void) for standard mains.
{
int k = 10;
char *string; // a C string is a char array, you need a pointer to point to it
char *sptr;
int *ptr;
string = "hello!";
sptr = string;
ptr = &k;
printf("%s \n", sptr); // no &. The %s format expects a char*.
printf("Sending pointer.\n");
// sendptr(ptr, sptr); // don't know what this function is, ignoring
return 0;
}
In C language, the & operator means you want to use the address of the variable (ie & = "the address of the variable").
int an_integer=2; // an_integer is a memory part where you want to store 2 ;)
printf("%d", &an_integer); // here you will print the address of the memory part where an_integer is stored (not 2, more something like 2510849).
The * operator in a declaration of variable means that you want to have a pointer to a memory part, when using it in the code, it means the "the value contained at the address of"
int an_integer=2;
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = &an_integer; // here you set the pointer ptr_integer to the address of an_integer
printf("%d", *ptr_integer); // here you print the value contained at the memory address stored in the ptr_integer
The [] operator means you want to store an array of something. In C, an array can be seen as a pointer to a memory space.
int an_integer[2]; // you declare an array of 2 integers
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = (int *)an_integer; // here you set the value of the pointer to the address of the array, you have to cast it into an (int *) to avoid compilation warnings.
For a start, I would suggest changing:
char string;
to:
char *string;
It's pretty clear that you want the string variable to be a string rather than a single character.
In addition, you probably want to change the two lines:
sptr = &string;
printf("%s \n", &sptr);
to:
sptr = string;
printf("%s \n", sptr);
but you could equally well just pass string itself to printf.
As for the sendptr(ptr, sptr);, we can't help that much without knowing more details about it.
To fix your second function (from your edit), change:
char fnamn[] = &fname;
to:
char *fnamn = fname;
or just use fname directly. You don't have to make a copy of the pointer and the former is for things like:
char fnamn[] = "I am a string literal";
I thought it might be helpful to adding something about the difference between a char array and a pointer to a string.
In function1 below, the local variable stringPtr is a pointer to memory which contains the string "hello!". The memory containing this string will be located in a read-only section of the program. The compiler decides where to place the string "hello!" and ensures that your local variable is initialised with this memory address.
You can modify the pointer stringPtr and change it to point somewhere else. But you cannot modify the memory it points at.
Also, it is perfectly valid to use the array access notation stringPtr[2] even though it is a pointer.
In function2 the compiler will set aside 9 bytes of space on the stack for the local variable stringArray and it will ensure that this array is initialised with the string "Goodbye!". As this memory is on the stack you can modify the contents of the array.
#include <stdio.h>
void function1(void)
{
char *stringPtr = "hello!";
printf("The first char is %c\n", stringPtr[0]);
printf("The next char is %c\n", *(stringPtr+1));
// This would cause a segmentation fault, stringPtr points to read-only memory
// stringPtr[0] = 'H';
}
void function2(void)
{
char stringArray[] = "Goodbye!";
printf("The first char is %c\n", stringArray[0]);
}
int main(void)
{
function1();
function2();
return 0;
}
First of all, the return type for main should be int, not void. void main() is only well-defined if your compiler documentation explicitly lists it as a legal signature. Otherwise you invoke undefined behavior. Use int main(void) instead.
Secondly, it's time for a quick crash course on strings, arrays, and pointers.
Unlike Java, C doesn't have a dedicated string datatype; rather, strings are represented as sequences of char values terminated by a 0. They are stored as arrays of char. The string literal "hello" is stored as a 6-element array of char (const char in C++). This array has static extent, meaning it is allocated at program startup and held until the program terminates. Attempting to modify the contents of a string literal invokes undefined behavior; it's best to act as though they're unwritable.
When an array expression appears in most contexts, the type of the expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array. That's one of the reasons the string = "hello"; statement doesn't work; in that context, the type of the expression "hello" is converted from "6-element array of char" to "pointer to char", which is incompatible with the target type (which, being char, isn't the correct type anyway). The only exceptions to this rule are when the array expression is an operand of either the sizeof or unary & operators, or if it is a string literal being used to initialize another array in a declaration.
For example, the declaration
char foo[] = "hello";
allocates foo as a 6-element array of char and copies the contents of the string literal to it, whereas
char *bar = "hello";
allocates bar as a pointer to char and copies the address of the string literal to it.
If you want to copy the contents of one array to another, you need to use a library function like strcpy or memcpy. For strings, you'd use strcpy like so:
char string[MAX_LENGTH];
strcpy(string, "hello");
You'll need to make sure that the target is large enough to store the contents of the source string, along with the terminating 0. Otherwise you'll get a buffer overflow. Arrays in C don't know how big they are, and running past the end of an array will not raise an exception like it does in Java.
If you want to guard against the possibility of a buffer overflow, you'd use strncpy, which takes a count as an additional parameter, so that no more than N characters are copied:
strncpy(string, "hello", MAX_LEN - 1);
The problem is that strncpy won't append the 0 terminator to the target if the source is longer than the destination; you'll have to do that yourself.
If you want to print the contents of a string, you'd use the %s conversion specifier and pass an expression that evaluates to the address of the first element of the string, like so:
char string[10] = "hello";
char *p = string;
printf("%s\n", "hello"); // "hello" is an array expression that decays to a pointer
printf("%s\n", string); // string is an array expression that decays to a pointer
printf("%s\n", p); // p is a pointer to the beginning of the string
Again, both "hello" and string have their types converted from "N-element array of char" to "pointer to char"; all printf sees is a pointer value.
Here's a handy table showing the types of various expressions involving arrays:
Declaration: T a[M];
Expression Type Decays to
---------- ---- ---------
a T [M] T *
&a T (*)[M]
*a T
a[i] T
&a[i] T *
Declaration: T a[M][N];
Expression Type Decays to
---------- ---- ---------
a T [M][N] T (*)[N]
&a T (*)[M][N]
*a T [N] T *
a[i] T [N] T *
&a[i] T (*)[N]
*a[i] T
a[i][j] T
&a[i][j] T *
Remember that the unary & operator will yield the address of its operand (provided the operand is an lvalue). That's why your char fnamn[] = &fname; declaration threw up the "invalid initializer" error; you're trying to initialize the contents of an array of char with a pointer value.
The unary * operator will yield the value of whatever its operand points to. If the operand isn't pointing anywhere meaningful (it's either NULL or doesn't correspond to a valid address), the behavior is undefined. If you're lucky, you'll get a segfault outright. If you're not lucky, you'll get weird runtime behavior.
Note that the expressions a and &a yield the same value (the address of the first element in the array), but their types are different. The first yields a simple pointer to T, where the second yields a pointer to an array of T. This matters when you're doing pointer arithmetic. For example, assume the following code:
int a[5] = {0,1,2,3,4};
int *p = a;
int (*pa)[5] = &a;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
p++;
pa++;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
For the first printf, the two pointer values are identical. Then we advance both pointers. p will be advanced by sizeof int bytes (i.e., it will point to the second element of the array). pa, OTOH, will be advanced by sizeof int [5] bytes, so that it will point to the first byte past the end of the array.
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
sptr = "hello!";
int *ptr;
ptr = &k;
printf("%s \n", sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}
I am learning C programming and I have a simple question about pointers...
I used the following code to play around with pointers:
#include <stdio.h>
int main (int argc, const char * argv[]) {
int * c;
printf("%x\n",c);
return 0;
}
When I print the value of C, I get back a 0. However, when I print &c (i.e. printf("&x\n",&c) I get an address in memory...
Shouldn't I be getting an address in memory when printing the pointer (i.e. printf("%x\n",c)?
--- EDIT ---
#include <stdio.h>
#include <stdlib.h>
int main (int argc, const char * argv[]) {
char * a = malloc(11);
printf("String please\n");
scanf("%s",a);
printf("%s",a);
}
The question is, why does printf("%s",a) returns the string instead of the address that is stored in a?
Shouldn't I use *a to follow the pointer and then print the string?
your current program is not correct. You define variable and do not set value before first use. the initial value is not guranteed for c, but you are lucky and it is equal to 0. It means that c points to nowhere. when you print &c you print address of variable c itself. So actually both versions print address.
printf is actually quite a complex function and can be made to do all sorts of tricks by giving it the right format specifier.
In your string example:
printf("%s", a)
the "%s" tells the printf function that the following variable should be treated as a string. In C, a string is a pointer to one or more char, terminated by a char containing 0. This is a pretty common request, which is why printf supports a format specifier "%s" that triggers this relatively complex behavior. If you want to print the address contained in the string pointer you have to use the format you found earlier:
printf("%x\n",a);
which tells printf to treat the contents of a as an unsigned integer, and print it in base 16.
*a would just be the value pointed to by a, which is just a single character.
You could print the single character with
printf("%c", *a);
Having int* c; If you print value of c, you get back a value that should be interpreted as a memory address of an integer value. In you example it might be 0 or something completely different as you are not initializing c.
If you print &c you get memory address of the pointer c (stored in stack).
#include <stdio.h>
int main (int argc, const char * argv[]) {
int * c;
int a=10;
c = &a;
printf("%x\n",c);
return 0;
}
This may clarify what happens when you make the int pointer point to something in memory.