void main()
{
char str[2][7] = {"1234567", "abcdefg"};
char** p = str;
printf("%d\n", *(p+1));
printf("%c\n", *(p+1));
}
The output is:
1631008309
5
Edit: Thank you. I see the '5' is only 0x35, other than str[0][4] I supposed to be. Why can't I get out str[0][4] instead of this strange 1631008309??
OMG, I'm foolish enough to ask this question! Thank you all, guys.
You're pointing a char** at the beginning of the memory allocated to your 2-d array.
When you add 1 to a pointer it moves you along by the sizeof the type pointed to, in this case the sizeof a char *, which is evidently 4 bytes in your system. Then you're dereferencing it and treating the result as an int (%d), which gives you the a765 I mentioned in my comment to unwind. When you dereference it and treat it as a char you correctly get 5.
[I see that unwind has deleted their answer, so just for completeness I'll add that the "a765" is the ASCII interpretation of the larger number you get (0x61373635).]
This line:
char** p = str;
makes no sense. str is an array of 2 arrays of 7 chars. When used in an expression context, it evaluates to a pointer to its first element, equivalent to:
&str[0]
which has type "pointer to array of 7 chars". That is in no way similar to a "pointer to pointer to char", which is the type of p. Any of these would make sense instead:
char *p = str[0];
char *p = str[1];
char (*p)[7] = str;
Using %d does not convert an ASCII string of alphanumerics into a number. Using %d means it expects that the value found will be interpreted as a binary representation of the number and converted TO ASCII for printing.
Note that the C standard defines that the main() program returns an int, not void.
Given the code:
#include <stdio.h>
int main()
{
char str[2][7] = {"1234567", "abcdefg"};
char** p = str;
printf("%d\n", *(p+1));
printf("%c\n", *(p+1));
return(0);
}
When compiled withgcc -o x -Wall x.c, you get the warnings:
x.c: In function ‘main’:
x.c:5: warning: initialization from incompatible pointer type
x.c:6: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘char *’
x.c:7: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’
(If you omit the -Wall, you don't get the format warnings.)
This tells you that you are passing a pointer to printf(). Printing a pointer is not going to be all that useful. However, the previous warning also tells you that you are mis-initializing the variable p. However, the net result is that p points to the start of the space in str. When you print
One interesting little quirk: normally, a string such as "1234567" includes a terminating NUL '\0'; in your arays, because you specified that the length of the array is 7, not 8, the terminating null is missing. Be careful how you print the strings!
Here's another variant of the code:
#include <stdio.h>
int main()
{
char str[2][7] = {"1234567", "abcdefg"};
char** p = str;
printf("%d\n", *(p+1));
printf("%c\n", *(p+1));
printf("%p %p %p -- %p %p %p\n", str, &str[0], &str[0][0], p, p+1, *(p+1));
printf("%.4s\n", (p+1));
return(0);
}
That gives me the following output (from an Mac):
1631008309
5
0xbffffa5e 0xbffffa5e 0xbffffa5e -- 0xbffffa5e 0xbffffa62 0x61373635
567a
Note that the addresses str, &str[0] and &str[0][0] all have the same value, and that p+1 is four bytes further along. When treated as a string, it prints the last three bytes of the first initializer and the first byte of the second.
Also, for fun, compiled with gcc -m64 -o x64 x.c, the output is:
1701077858
b
0x7fff5fbff9e0 0x7fff5fbff9e0 0x7fff5fbff9e0 -- 0x7fff5fbff9e0 0x7fff5fbff9e8 0x676665646362
bcde
I understand your confusion, the two statements is exactly the same.
Both statements cast *(p + 1) to an pointer to an integer prior dereferencing it, the default is to cast everything to an integer in a va_arg argument.
printf then truncates the integer to a char prior printing it in the second printf statement.
This code snippet makes it more clear what is going on:
void main()
{
char str[2][7] = {"1234567", "abcdefg"};
char** p = str;
printf("%d\n", *(p+1));
printf("%c\n", *(p+1));
int n = *(p+1);
char c = *(p+1);
printf("0x%08X\n", n);
printf("0x%08X\n", c);
}
Which outputs:
1631008309
5
0x61373635
0x00000035
Type safety in stdarg is explained here: stdarg
Related
In my C program i assign a string in one integer variable and i print with percentage %s it will print that string with warning integer to pointer without cast and print with %d it print 134513904 then i change my string value and print with %d "134513904" is printing what is this value and how integer variable storing a string value in int variable?
enter code here
#include<stdio.h>
main()
{
int a="naveen";
printf("%d\n",a);
printf("\n%s\n",a);
if("naveen")
{
printf("hi");
}
int_point.c: In function ‘main’:
int_point.c:22:8: warning: initialization makes integer from pointer without a cast [enabled by default]
int a="naveen";
^
int_point.c:24:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("\n%s\n",a);
^
134513920
naveen
hi
The following assigns a pointer (not a string) to s:
const char *s = "navven";
That means the following assigns a pointer (not a string) to a:
int a = "naveen";
Computers don't really see a difference between a pointer and number. They're both things that fit in their registers. And some people take advantage of that fact. So while the compiler warns you that you are doing something wrong, it still lets you treat the pointer as a number.
So a is ends up with the value of the pointer if it were an int. That's not safe to do. Not quite. While you can't use an int safely, you can use an intptr_t safely.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
int main(void) {
const char *p1 = "naveen";
printf("%p %s\n", p1, p1);
intptr_t i = (intptr_t)p1;
printf("0x%" PRIxPTR "\n", i);
const char *p2 = (const char*)i;
printf("%p %s\n", p2, p2);
return 0;
}
Output:
0x51ee878764 naveen
0x51ee878764
0x51ee878764 naveen
I have been studying a code on Programming in C lately. I got stuck here while dealing with two dimensional strings and pointers. Also the functions printf(), putchar(), and puts() are confusing! Please help me out with the following snippet:
#include<stdio.h>
int main()
{
char wer[3][4]= {"bag", "let", "bud"};
char (*ptr)[4]=wer;
printf("%d %d %d\n",ptr, ptr+1, ptr+1); // points to bag, let and bud respectively
printf("%d %d %d\n",wer, wer+1, wer+1); // points to bag, let and bud respectively
printf("%d %d %d\n", (*ptr), (*ptr+1), (*ptr +2)); // points to b,a,g respectively
printf("%s\n",*(ptr+1)); //prints let
printf("%s\n", (ptr+1)); //prints let
printf("%s\n", (*ptr +1)); //prints ag
puts(*(ptr+1)); //prints let
//puts((ptr+1)); //gives error
puts((*ptr+1)); //prints ag
putchar(**(ptr+1));//prints l
putchar(*(*ptr +1));//prints a
return 0;
}
I want to know why do *(ptr+1) and (ptr+1) both work for printf while (ptr+1) gives an error for puts. Also I know that putchar takes an integer argument. Why do we use double pointer here?
Your ptr variable is of type char (*)[4] (a pointer to char array). The prototype of puts is:
int puts(const char *s);
So, as your compiler probably says, puts expects a pointer on char but you give an argument of type char (*)[4].
I want to know why do *(ptr+1) and (ptr+1) both work for printf while (ptr+1) gives an error for puts.
The argument types are not checked on the call to printf (probably because printf takes variadic arguments). Add -Wall in your CFLAGS to add more warnings and your compiler should emit a warning about this.
Also I know that putchar takes an integer argument. Why do we use double pointer here?
You dereference ptr twice to get a char (you can also do (*ptr)[1]). This char is implicitly cast into int when you call putchar.
SORRY, I misread my results, *p and p are different
I am trying to make an understanding about array of pointers.
I wrote
int n[5] = {1,2,3,4,5};
int *p[5];
for(i = 0; i < 5; i++){
p[i] = &n[i];
}
so far so good.
and I understand that
printf("%0x\n", *p);
gives me the address of the first pointer in the array.
what's troubling me is p, just p, no asterisk, no brackets.
because
printf("%0x\n", *p);
printf("%0x\n", p);
[give me exactly the same thing.
Why is p also the address of the first pointer in the array??] WRONG, SORRY!
What exactly does p mean, when an array of pointers like above is declared?
A related question
int main(int argc, char *argv[]){
for(int i = 0; i < argc; i++){
printf("%s\n",argv[i]); //why not *argv[i]??
}
}
since argv is declared as an array of pointers, shouldn't argv[i] yield the address instead of the string where it points to? because it doesn't have an asterisk in front it.
Thanks in advance.
p, just p, no asterisk, no brackets gives the address of the first element of the array p[]. *p on the other hand gives the value of the first element of the array p[], which happens to be the address of the first element of the array n[], according to the code you show.
Lets take an example, assuming an integer is of size 4 bytes and an address if of size 8 bytes, and the first program that you showed.
int n[5] = {1,2,3,4,5};
int *p[5];
for(i = 0; i < 5; i++)
{
p[i] = &n[i];
}
The arrays would look something like this.. (addresses are assumed for explanation purpose, they are not real).
n[] = { 1, 2, 3, 4, 5}; //these are integers
// ^ ^ ^ ^ ^
// 100 104 108 112 116 these are the addresses of the elements of array n[]
p[] = { 100, 104, 108, 112, 116}; // these are pointer to integers
// ^ ^ ^ ^ ^
// 200 208 216 224 232 these are adddress of the elements of array p[]
Now, p, just p, no asterisk, no brackets would give the value 200, which is the address of the first element of the array p[].
Like wise n would give the value 100.
*p would give the value 100 which is the element stored in the first position of the array p[].
When you use just p it decays to a pointer to the first element in the array p, i.e. p is equivalent to &p[0].
When you dereference that pointer you get the pointer stored in p[0]. I.e. when you do *p it's the same as doing as doing *&p[0], and the dereference and address-of operators take out each-other giving you only p[0], which in your case is equal to &n[0].
Also note that when you want to print pointers using printf you should be using the format "%p" (and really pass a void * as argument).
The not really related question is because argv is an array of pointer to characters. For any valid index i the expression argv[i] gives you a pointer, of type char *. If you dereference this pointer you get the character pointed to by argv[i], i.e. a single character.
Given,
int n[5] = {1,2,3,4,5};
int *p[5];
for(int i = 0; i < 5; i++){
p[i] = &n[i];
}
printf("0x%p\n", *p);
printf("0x%p\n", p);
The output is definitely not expected to be the same.
I get
0x0x7fffe0c40b40
0x0x7fffe0c40b60
on my desktop.
If I use:
printf("%0x\n", *p);
printf("%0x\n", p);
I get the following warning when compiled using gcc -Wall
soc.c: In function ‘test’:
soc.c:12:4: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%0x\n", *p);
^
soc.c:13:4: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat=]
printf("%0x\n", p);
Even then, I get the following output:
3ef18920
3ef18940
As you can see, they are not the same.
Perhaps you are seeing symptoms of undefined behavior due to use of incorrect format specifier.
See the output of both forms at http://ideone.com/73UoDa.
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.
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);
}