void
bar (char *arg, char *targ, int len)
{
int i;
for (i = 0; i < len; i++)
{
*targ++ = *arg++;
}
}
learning c right now, a friend sent me this snippet and I can't understand what it does. An explanation of the pointer portion would be helpful. From my understanding, it seems to be copying the value of arg into targ for i chars?
A pointer is a variable that stores an address. This address can be the address
of another variable:
int a = 18;
int *pa = &a;
or it can be the start of a dynamically allocated memory block:
int *p = malloc(sizeof *p);
The important thing is that pointers allow you access the values behind an
address. You do that by dereferencing the pointer using the *-operator:
int a = 18;
int *pa = &a;
*pa = 10;
printf("a=%d\n", a); // will print 10
For these kind of examples, this might not seem like a big deal, but it is,
because you can pass pointers to functions and those function can then interact
with the memory pointed to by the pointer, depending on the memory block, even
modifiy it.
Pointers can also point to the start of sequence of objects, for example to the
start of an array:
int arr[] = { 1, 3, 5 };
int *p = arr;
Note p[0] is 1, p[1] is 3 and p[2] is 5. It is also possible to change the
values by doing p[1] = -14;. This is also dereferencing, but you also can use the
*-operator:
p[1] = 12;
// is equivalent to
*(p + 1) = 12;
And that's what your snippet is using. Forget for a second the loop. Take a look
at this line:
*targ++ = *arg++;
This can be rewritten as:
targ[0] = arg[0];
targ = targ + 1; // or targ = &(targ[1])
arg = arg + 1; // or arg = &(arg[1])
Now it's more clear what it is doing. It copies the value of first character
pointed to by arg to the position where targ is pointing to. After that both
arg and targ are incremented to advance to the next element in the
sequence.1
So what the loop is doing is copying len objects pointed to by arg to
targ. This could be used to copy a string into another char array. But it is
not safe, as it is not clear whether the '\0'-terminating byte is is copied
and it is not clear whether the buffers are large enough (meaning larger than
len). If they are not strings but sequences of bytes, then this function would
be OK.
In C a string is just a sequence of characters that ends with the '\0'-terminating byte.
For that reason they are stored using char arrays and are passed to functions
as pointers of char, that point to the start of the string. We could rewrite
this function in a more safer way like this:
int safe_copy_string(char *dest, char *source, size_t dest_size)
{
if(dest == NULL || source == NULL)
return 0;
if(dest_size == 0)
return 1; // no space to copy anything
// copying one element less than dest_size
// that last element if dest should be \0
for(size_t i = 0; i < dest_size - 1; ++i)
{
*dest++ = *source++;
if(*(source - 1) == '\0')
break; // copied sources's 0-terminating byte
}
dest[dest_size - 1] = 0; // making sure it is 0-terminated
return 1;
}
Footenotes
1It's worth mentioning the ++-operator here. This is the post-increment
operator which is used to add 1 to the operand (for integers), in case of a pointer
to advance the pointer by 1 thus making it point to the next object.
When you do:
int a = 6;
int b = a++;
// a == 7, b == 6
a is initialized with 6. When initializing b, the compiler will use the
current value of a for the initialization, however the post-increment
operator has the side effect that it will increment the value of a by 1. When
this exactly happens is define by the rules of sequence points. What
matters is that in the initialization of b, the current value of a is used
and after the assignment a will have a the new value.
A pointer points to a data, and usually contains the memory address of the data. The pointer is a normal 'c' variable.
operator '*' applied at the time, when the pointer is used, tells the compiler to access data, at the location denoted by the pointer.
Operator '++', applied to the pointer, increments its value so, that it points to the next data element, adjacent to the previous one. So, for 'char*' pointers, it increments the address by '1' to point to the next char in the string.
In your case *targ++ means: access data referenced by the pointer 'targ' and then increment the value of the pointer.
*targ++ = *arg++;
In the above expression the program takes char pointed by 'arg' and assigns it to the char location referenced by 'targ'. Then it increments values of the pointers 'arg' and 'targ'.
Here is the function you provided, exploded with a line-by-line explanation of the function. At the end are revisions to make the function slightly safer.
This line declares the return type of the function. The type 'void' indicates that this function returns nothing (a procedure as opposed to a function).
void
This line declares the name of the function, 'bar', and then presents a list of three arguments, 'arg', 'targ', and 'len'. The types of these arguments are 'arg' is a pointer to a character, and is how you pass a string in C; 'targ' is also a pointer to a character, and again is how you pass a string in C; and 'len' is an int(eger).
bar (char *arg, char *targ, int len)
This symbol '{' indicates that the body of the function definition follows.
{
This line declares that 'i' is a variable of type 'int'(eger), and this variable has space reserved on the stack for the duration of the function.
int i;
This line declares a repetition loop using the 'for' keyword. Between the parenthesis appears three sub-parts: the first part contains initialization prior to loop start, and the variable 'i' is set to the value 0; The second part contains an expression that is evaluated to determine whether to continue the loop, in this case the expression 'i < len' is checked every pass through the loop, so the loop terminates when the value of i becomes greater than or equal to the value of 'len'; the third part contains an expression that is performed at the end of each loop pass.
for (i = 0; i < len; i++)
This line '{' opens a statement body for the for loop,
{
This line is where the interesting work of the function is performed. As explained above, the for loop will be executed once for each value of 'i' in the list (0,1,2,3, ... ,len-1), seriatim. Note that the loop ends when 'i' has the value 'len'. Refer to the function declaration line above, how the variables 'arg' and 'targ' are pointers to character? These lines de-reference these variables to access the pointer location(s).
Suppose the line were '*targ = *arg', then the R-value *arg would be the contents at the current location pointed at by 'arg', and the L-value '*targ' would be the current location pointed at by 'targ'. Where the character 'x' stored at '*arg', then 'x' would be copied to '*targ', overwriting the previous contents.
*targ++ = *arg++;
The '++' symbols after the pointers do not affect the characters pointed at by the pointers, but increment the pointers (due to precedence of the '*' and '++' operators). That one line could be rewritten as,
*targ = *arg;
arg++;
targ++;
This line '}' closes the statement body for the for loop,
}
This symbol '}' matches and closes the body of the function definition.
}
You should always check for valid arguments to functions. And you should check that values do not overrun their buffers. I have added a few statement to the function to make it more robust. As presented, the function behaves like 'memcpy', and does not care about terminated 'strings'; I have added 'endc' to detect string end.
char* //return the destination, for further processing, e.g. strlen()
bar (char *arg, char *targ, int len)
{
int ndx; //try searching for 'i' in a big source file sometime...
char endc; //temporary to detect null character, more like 'strncpy'
if( (!arg) || (!targ) || (len<1) ) return targ;
for (ndx = 0; ndx < len; ndx++)
{
endc = *targ++ = *arg++;
if( !endc ) break; //comment this out for 'memcpy' behavior
}
}
Some would say checking the length is not needed. That is true for simple functions, but complex functions may reveal that this habit is rewarding.
Related
I am trying to write a function that is given a string of text (which is to be a shell command) and now I just need to extract words, so delete spaces and save each word in a pointer to pointer to char. My idea was to do it this way, but gcc compilers gives back a warning that "return from incompatible pointer type"
Code:
char **getargs(char *command)
{
static char arguments[MAXARG][CMDLENGTH];
int i = 0, word = 0, letter = 0, status = OUT;
while(command[i] != '\0')
{
if(isspace(command[i]) && status == IN)
{
arguments[word][letter] = '\0';
letter = 0;
word++;
status = OUT;
i++;
}
else if(!isspace(command[i]) && status == OUT)
{
arguments[word][letter] = command[i];
status = IN;
letter++;
i++;
}
else if(!isspace(command[i] && status == IN))
{
arguments[word][letter] = command[i];
letter++;
i++;
}
else if(isspace(command[i]) && status == OUT)
i++;
}
return arguments;
}
EDIT: Additionally, I have also figured out that in order to return a pointer that was declared locally it needs to be declared as static, why is that?
Your function signature promises to return a char **, a pointer to pointer to char. That means if the returned value is r, then *r will have to be a pointer to some character(s) you have put somewhere. The calling function could define a char-pointer cp = *r, and then *cp would be the first character, and printf(cp); would print the first word your function found.
But this is not what you're actually returning: you're not returning a pointer to a pointer, and that is why the compiler warns.
What you are returning is a two-dimensional array - that is, MAXARG*CMDLENGTH chars, one after the other - and that array is automatically returned in the form of a pointer to its start. So r is a pointer to the start of the array, *r is the first item in the array, which is some character - but certainly not a pointer (chars are often a single byte, pointers are usually 4 or 8 bytes and contain some memory address). Usage in accordance with your function signature would go completely wrong: cp = *r would take 4 or 8 of your characters and interpret them as one memory address...
Solutions are in the post linked by Davide in the comments and other answers to that question. Your static array inside a function can also work, as long as the function signature makes clear it will return a pointer - for example
void *getargs(char *command)
which could then be called from somewhere else and put in a pointer-to-arrays-of-the-correct-size,
char (*r)[CMDLENGTH] = getargs("one two three"); // r = pointer to char[CMDLENGTH]
printf("first arg: %s\n", r[0]);
printf("second arg: %s\n", r[1]);
printf("third arg: %s\n", r[2]);
This gets a little ugly; personally I'd prefer solution #2 in the linked post.
Let's say I have function that has a char array as its parameter and char* as its return type. I want to return a pointer to the subarray of the parameter array.
For example : char str[] = "hi billy bob";
I want my function to return "billy bob";
Let's say in the body of my function I was able to get the index
of where I want the subarray to start.
char* fun(const char s1[]) {
int index = a random int;
/* char *p = *(s1[index1]); */
return p;
}
I'm having trouble with the commented out line.
Simply use
const char *p = &str[index]; /* may also write p = str + index */
return p;
The above takes the address of the character at index index -- which is a pointer to char array beginning at this index. The string continues until the first '\0' character which is the end of the original str.
In your case, if you want the output to be "billy bob" (Note that you cannot change the capitalization unless you modify the string or return a new one) you should set index = 3;.
It gets more involved when you want to take a substring of str. Then you either have to set str[end_index]='\0' or use malloc to allocate a new array and copy the relevant part.
Some information regarding the two syntax options
In C, the expression a[i] is equivalent to *(a+i). I.e., take the pointer a, move it forward i elements (chars in your case) and then return the element at the resulting address.
If you prefix a[i] with an & operator to get the address of that character. So &a[i] may be written as &*(a+i). The operators '&' and '*' cancel each other and you are left with a+i.
What you want is this
char *random_sub_string(const char *string)
{
size_t length;
if (string == NULL)
return NULL;
length = strlen(string);
return string + rand() % length;
}
char *fun(const char str[])
{
int index = x; /* where `x' is some non-negative value less than the
length of the input string */
return str + index;
}
This is the cleanest way of returning the string you're looking to return. The main idea here is that, in C, a string is defined as a null-terminated array of characters. Null-terminated means the array contains the \0 character, and the location of the \0 denotes the end of the string. Moreover, a char[] and char * are both pointers to a char. Thus, they can be accessed in the same way. In the return statement above, we make use of pointer arithmetic to compute a pointer to a substring of the input string. If you're not familiar with pointer arithmetic, it would be a good idea to read up on it.
I am trying to remove first semicolon from a character arrary whose value is:
Input: ; Test: 876033074, 808989746, 825766962, ; Test1:
825766962,
Code:
char *cleaned = cleanResult(result);
printf("Returned BY CLEAN: %s\n",cleaned);
char *cleanResult(char *in)
{
printf("Cleaning this: %s\n",in);
char *firstOccur = strchr(in,';');
printf("CLEAN To Remove: %s\n",firstOccur);
char *restOfArray = firstOccur + 2;
printf("CLEAN To Remove: %s\n",restOfArray); //Correct Value Printed here
char *toRemove;
while ((toRemove = strstr(restOfArray + 2,", ;"))!=NULL)
{
printf("To Remove: %s\n",toRemove);
memmove (toRemove, toRemove + 2, strlen(toRemove + 2));
printf("Removed: %s\n",toRemove); //Correct Value Printed
}
return in;
}
Output (first semicolon still there): ; Test: 876033074,
808989746, 825766962; Test1: 825766962;
Regarding sizeof(cleaned): using sizeof to get the capacity of an array only works if the argument is an array, not a pointer:
char buffer[100];
const char *pointer = "something something dark side";
// Prints 100
printf("%zu\n", sizeof(buffer));
// Prints size of pointer itself, usually 4 or 8
printf("%zu\n", sizeof(pointer));
Although both a local array and a pointer can be subscripted, they behave differently when it comes to sizeof. Thus, you cannot determine the capacity of an array given only a pointer to it.
Also, bear this in mind:
void foo(char not_really_an_array[100])
{
// Prints size of pointer!
printf("%zu\n", sizeof(not_really_an_array));
// Compiles, since not_really_an_array is a regular pointer
not_really_an_array++;
}
Although not_really_an_array is declared like an array, it is a function parameter, so is actually a pointer. It is exactly the same as:
void foo(char *not_really_an_array)
{
...
Not really logical, but we're stuck with it.
On to your question. I'm unclear on what you're trying to do. Simply removing the first character of a string (in-place) can be accomplished with a memmove:
memmove( buffer // destination
, buffer + 1 // source
, strlen(buffer) - 1 // number of bytes to copy
);
This takes linear time, and assumes buffer does not contain an empty string.
The reason strcpy(buffer, buffer + 1) won't do is because the strings overlap, so this yields undefined behavior. memmove, however, explicitly allows the source and destination to overlap.
For more complex character filtering, you should consider traversing the string manually, using a "read" pointer and a "write" pointer. Just make sure the write pointer does not get ahead of the read pointer, so the string won't be clobbered while it is read.
void remove_semicolons(char *buffer)
{
const char *r = buffer;
char *w = buffer;
for (; *r != '\0'; r++)
{
if (*r != ';')
*w++ = *r;
}
*w = 0; // Terminate the string at its new length
}
You are using strcpy with overlapping input / output buffer, which results in undefined behavior.
You're searching for a sequence of three characters (comma space semicolon) and then removing the first two (the comma and the space). If you want to remove the semicolon too, you need to remove all three characters (use toRemove+3 instead of toRemove+2). You also need to add 1 to the strlen result to account for the NUL byte terminating the string.
If, as you say, you just want to remove the first semicolon and nothing else, you need to search for just the semicolon (which you can do with strchr):
if ((toRemove = strchr(in, ';')) // find a semicolon
memmove(toRemove, toRemove+1, strlen(toRemove+1)+1); // remove 1 char at that position
I've been studying C, and I decided to practice using my knowledge by creating some functions to manipulate strings. I wrote a string reverser function, and a main function that asks for user input, sends it through stringreverse(), and prints the results.
Basically I just want to understand how my function works. When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
I guess answering this question would tell me: Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now? I want to know whether I'm sending a duplicate of the array tempstr, or a memory address.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
printf("\nEnter a string:\n\t");
char tempstr[1024];
gets(tempstr);
char *revstr = stringreverse(tempstr, revstr); //Assigns revstr the address of the first character of the reversed string.
printf("\nReversed string:\n"
"\t%s\n", revstr);
main();
return 0;
}
char* stringreverse(char* tempstr, char* returnptr)
{
char revstr[1024] = {0};
int i, j = 0;
for (i = strlen(tempstr) - 1; i >= 0; i--, j++)
{
revstr[j] = tempstr[i]; //string reverse algorithm
}
returnptr = &revstr[0];
return returnptr;
}
Thanks for your time. Any other critiques would be helpful . . only a few weeks into programming :P
EDIT: Thanks to all the answers, I figured it out. Here's my solution for anyone wondering:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stringreverse(char* s);
int main(void)
{
printf("\nEnter a string:\n\t");
char userinput[1024] = {0}; //Need to learn how to use malloc() xD
gets(userinput);
stringreverse(userinput);
printf("\nReversed string:\n"
"\t%s\n", userinput);
main();
return 0;
}
void stringreverse(char* s)
{
int i, j = 0;
char scopy[1024]; //Update to dynamic buffer
strcpy(scopy, s);
for (i = strlen(s) - 1; i >= 0; i--, j++)
{
*(s + j) = scopy[i];
}
}
First, a detail:
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
That prototype should go outside main(), like this:
char* stringreverse(char* tempstr, char* returnptr);
int main()
{
As to your main question: the variable tempstr is a char*, i.e. the address of a character. If you use C's index notation, like tempstr[i], that's essentially the same as *(tempstr + i). The same is true of revstr, except that in that case you're returning the address of a block of memory that's about to be clobbered when the array it points to goes out of scope. You've got the right idea in passing in the address of some memory into which to write the reversed string, but you're not actually copying the data into the memory pointed to by that block. Also, the line:
returnptr = &revstr[0];
Doesn't do what you think. You can't assign a new pointer to returnptr; if you really want to modify returnptr, you'll need to pass in its address, so the parameter would be specified char** returnptr. But don't do that: instead, create a block in your main() that will receive the reversed string, and pass its address in the returnptr parameter. Then, use that block rather than the temporary one you're using now in stringreverse().
Basically I just want to understand how my function works.
One problem you have is that you are using revstr without initializing it or allocating memory for it. This is undefined behavior since you are writing into memory doesn't belong to you. It may appear to work, but in fact what you have is a bug and can produce unexpected results at any time.
When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
Yes. When arrays are passed as arguments to a function, they are treated as regular pointers, pointing to the first element in the array. There is no difference if you assigned &temp[0] to a char* before passing it to stringreverser, because that's what the compiler is doing for you anyway.
The only time you will see a difference between arrays and pointers being passed to functions is in C++ when you start learning about templates and template specialization. But this question is C, so I just thought I'd throw that out there.
When I call it with 'tempstr' as the first param, is that to be understood as the
address of the first element in the array? Basically like saying &tempstr[0],
right?
char tempstr[1024];
tempstr is an array of characters. When passed tempstr to a function, it decays to a pointer pointing to first element of tempstr. So, its basically same as sending &tempstr[0].
Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now?
No difference. You might do -
char* pointer = tempstr ; // And can pass pointer
char *revstr = stringreverse(tempstr, revstr);
First right side expression's is evaluavated and the return value is assigned to revstr. But what is revstr that is being passed. Program should allocate memory for it.
char revstr[1024] ;
char *retValue = stringreverse(tempstr, revstr) ;
// ^^^^^^ changed to be different.
Now, when passing tempstr and revstr, they decayed to pointers pointing to their respective first indexes. In that case why this would go wrong -
revstr = stringreverse(tempstr, revstr) ;
Just because arrays are not pointers. char* is different from char[]. Hope it helps !
In response to your question about whether the thing passed to the function is an array or a pointer, the relevant part of the C99 standard (6.3.2.1/3) states:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
So yes, other than the introduction of another explicit variable, the following two lines are equivalent:
char x[] = "abc"; fn (x);
char x[] = "abc"; char *px = &(x[0]); fn (px);
As to a critique, I'd like to raise the following.
While legal, I find it incongruous to have function prototypes (such as stringreverse) anywhere other than at file level. In fact, I tend to order my functions so that they're not usually necessary, making one less place where you have to change it, should the arguments or return type need to be changed. That would entail, in this case, placing stringreverse before main.
Don't ever use gets in a real program.. It's unprotectable against buffer overflows. At a minimum, use fgets which can be protected, or use a decent input function such as the one found here.
You cannot create a local variable within stringreverse and pass back the address of it. That's undefined behaviour. Once that function returns, that variable is gone and you're most likely pointing to whatever happens to replace it on the stack the next time you call a function.
There's no need to pass in the revstr variable either. If it were a pointer with backing memory (i.e., had space allocated for it), that would be fine but then there would be no need to return it. In that case you would allocate both in the caller:
char tempstr[1024];
char revstr[1024];
stringreverse (tempstr, revstr); // Note no return value needed
// since you're manipulating revstr directly.
You should also try to avoid magic numbers like 1024. Better to have lines like:
#define BUFFSZ 1024
char tempstr[BUFFSZ];
so that you only need to change it in one place if you ever need a new value (that becomes particularly important if you have lots of 1024 numbers with different meanings - global search and replace will be your enemy in that case rather than your friend).
In order to make you function more adaptable, you may want to consider allowing it to handle any length. You can do that by passing both buffers in, or by using malloc to dynamically allocate a buffer for you, something like:
char *reversestring (char *src) {
char *dst = malloc (strlen (src) + 1);
if (dst != NULL) {
// copy characters in reverse order.
}
return dst;
}
This puts the responsibility for freeing that memory on the caller but that's a well-worn way of doing things.
You should probably use one of the two canonical forms for main:
int main (int argc, char *argv[]);
int main (void);
It's also a particularly bad idea to call main from anywhere. While that may look like a nifty way to get an infinite loop, it almost certainly will end up chewing up your stack space :-)
All in all, this is probably the function I'd initially write. It allows the user to populate their own buffer if they want, or to specify they don't have one, in which case one will be created for them:
char *revstr (char *src, char *dst) {
// Cache size in case compiler not smart enough to do so.
// Then create destination buffer if none provided.
size_t sz = strlen (src);
if (dst == NULL) dst = malloc (sz + 1);
// Assuming buffer available, copy string.
if (dst != NULL) {
// Run dst end to start, null terminator first.
dst += sz; *dst = '\0';
// Copy character by character until null terminator in src.
// We end up with dst set to original correct value.
while (*src != '\0')
*--dst = *src++;
}
// Return reversed string (possibly NULL if malloc failed).
return dst;
}
In your stringreverse() function, you are returning the address of a local variable (revstr). This is undefined behaviour and is very bad. Your program may appear to work right now, but it will suddenly fail sometime in the future for reasons that are not obvious.
You have two general choices:
Have stringreverse() allocate memory for the returned string, and leave it up to the caller to free it.
Have the caller preallocate space for the returned string, and tell stringreverse() where it is and how big it is.
I am speaking in Standard, K&R C.
Given:
const char a[] = {1, 2, 3};
const char *p = NULL;
Are these two statements equivalent:
*p = a;
p = a;
Each of them would be on the third line of the snippet.
1 and 2 certainly don't look the same.
What's the difference between the two then?
No.
p = a initializes the pointer to point to something else (usually it copies another pointer or you will point to a reference, ala p = &a.
*p = a initializes what p refers to. You are "dereferencing" (looking at) what p points to. If p points to NULL as in your example, you will crash (this is good! you do not want to accidentally access something and mess your program up).
In this case, p = a will point to the first of the array a[], and *p = a will attempt to change the first of the array (it won't work; you have it declared const).
Here is a small example program in C++, with almost identical syntax to C.
#include <iostream>
int main()
{
char arr[5] { 'a', 'b', 'c' }; // arr[3] and arr[4] are set to 0
char *ptr = arr; //point to 'a'
for (int i = 0; i != 5; i++)
{
*ptr = 'f'; //this changes the array
ptr++; //this changes what the pointer points to; moves it to next in array
}
for (int i = 0; i != 5; i++)
{
std::cout << *ptr << " ";
}
//outputs f f f f f
}
The * operator is what we call the dereference operator. To understand what it does, you must understand exactly what a pointer is.
When you do
char *p;
the "variable" p does not use the same amount of memory as a normal char, it uses more memory: it uses the amount of memory needed to correctly identify a memory position in your computer. So, let's say you use a 32-bit architecture, the variable p occupies 4 bytes (not the 1 byte you would expect from a char).
So, when you do
p = a;
you see clearly that you are changing the contents of the variable p, that is, you are putting another 32-bit number inside it: you are changing the address it is pointing to.
After that line executes, the value of p is the memory address of the character array a.
Now for the dereference operator. When you do
*p = 'Z';
you are telling the compiler that you want to store the value 'Z' ON THE ADDRESS pointed by p. So, the value of p remains the same after this line: it continues to point to the same address. It's the value of this address that has changed, and now contains 'Z'.
So, the final effect of
char a[] = {'a', 'b', 'c'};
char p = a;
*p = 'Z';
is the same as changing the first position of the array a to 'Z', that is:
char a[] = {'a', 'b', 'c'};
a[0] = 'Z';
NOTE: there is a difference when making a pointer point to an array: the variable that contains the array contains only the address of the first element, so a is the same as "the starting address of the array".
Usually you will see the & operator. It is an operator used to obtain the memory address of a variable. For example:
int number = 42;
int pointer = &number;
printf("%d", *pointer);
Here we have them all. The first line creates an integer variable and stores 42 inside it.
The second line creates a pointer to an integer, and stores the address of the variable number inside it.
The third line reades the value on the address pointed by the pointer.
So, the trick is to read *x as on the address pointed by x and &x as the address of x.
The first dereferences a null pointer, and tries to assign it the address of the array. This will be a compiler error, because char != char []. If it weren't, it would likely crash.
The second sets p to point to the the array.
I think you are mistaking:
char a[8];
char *p=a;
which is legal and does the same as:
char a[8];
char *p=NULL;
p=a;
with:
char a[8];
char *p=NULL;
*p=a;
which as others said would generate a compile error or a segmentation fault.
In the left side of declarations you should read *x as pointer(x) while in
statements it must be read as value_pointed_by(x). &x on the other hand
would be pointer_to(x)
Here's a trick I used when I learned C (and still use today).
Whenever you see the * in front of a variable in your code, automatically read it as "what is pointed to by".
So you should be able to easily see that setting "p" to "a" is very different from setting "what is pointed to by p" to "a".
Also, since p is supposed to be pointing at a char, setting that char p is pointing at (currently the "char" at memory location 0 assuming null is 0) to a char pointer (a) is probably going to fail at compile time if you are lucky (depending on your compiler and lint settings it may actually succeed.)
from comment:In a function declaration like f(char c), I usually try to separate out the variable name from the rest of it--so it would be f( (char) c). so c is a char*. Exactly like a variable definition.
Also & usually reads as "The address of", but that gets even more iffy. A few examples of how I read things to myself. May or may not help you.
int a[] = {1,2,3}; // I mentally parse this as (int[]) a, so a is an int array.
int *p; // p is a pointer to "integers"
int i;
p=a; // p acts exactly as a does now.
i=*p; // i is "What is pointed to by" p (1)
i=p; // i is some memory address
i=*a; // i is what is pointed to by a (1)
i=p[1]; // Don't forget that * and [] syntax are generally interchangable.
i=a+1; // Same as above (2).
p=&i; // p is the address of i (it can because it's a pointer)
// remember from hs algebra that = generally reads as "is", still works!
*p=7; // what is pointed to by p (i) is 7;
a=*i; // whoops, can't assign an array. This is the only difference between
// arrays and pointers that you will have to deal with often, so feel
// free to use which ever one you are more comfortable with.
char c='a';
char * d = &c;// d is a char pointer, and it is the address of c
char ** e ; // e is a pointer to a memory location containing
// a pointer to a char!
e=&d; // gets d's address. a pointer to a pointer gets
// the address of a pointer. Messy but gets the job done
**e=5; // what is pointed to by what is pointed to by e is 5.
*e=&'f'; // what is pointed to by e (which is a char * itself, and is still d!)
// is set to the address of the memory location holding the value 'f'.
// does not change c or e, just d!
I haven't touched c in 10 years, so some of this may be a bit wrong, but it helps me to read it out loud that way.
No, they are not equivalent
If p = NULL, then doing *p = a will give you a segmentation fault.
Because "*p" dereferences the pointer wouldnt this make "p" a "char**" ?
This would point "p" to the first array as expected.
I guess they are not the same.