Fundamental C pointer question using 'strcpy'
Man, pointers continue to give me trouble. I thought I understood the concept.(Basically, that you would use *ptr when you want to manipulate the actual memory saved at the location that ptr points to. You would just use ptr if you would like to move that pointer by doing things such as ptr++ or ptr--.) So, if that is the case, if you use the asterisk to manipulate the files that the pointer is pointing to, how does this work:
char *MallocAndCopy( char *line ) {
char *pointer;
if ( (pointer = malloc( strlen(line)+1 )) == NULL ) {
printf( "Out of memory!!! Goodbye!\n" );
exit( 0 );
}
strcpy( pointer, line );
return pointer;
}
malloc returns a pointer, so I understand why the "pointer" in the if conditi开发者_如何转开发on does not utilize the asterisk. However, in the strcpy function, it is sending the CONTENTS of line to the CONTENTS of pointer. Shouldn't it be:
strcpy( *pointer, *line);
????? Or is my understanding of pointers correct and that is just the way that the strcpy function works?
A C-style string is an array of character bytes. When you pass an array around as a pointer to the array type, the pointer contains the address of the first element of the array.
The strcpy
function takes the pointer to the first char
of the source array (which is the start of the string) and the pointer to the first char
in the destination array, and iterates over the source until it reaches a '\0'
character, which terminates the string.
That's also why when you call malloc
, the size that you pass to it is strlen(line)+1
, because you need to allocate one more byte for the termination character (as far as I know).
char* strcpy(char *destination, const char *source)
is the signature for strcpy
. It expects to get pointers as arguments. In your instance, pointer
is already a pointer, and so is line
.
strcpy
will take the pointers source
and destination
, and copy the underlying bytes pointed at from source
to destination
until it either hits the \0
(NULL) byte in the string pointed to by source
, or if it segmentation faults because it never encounters that byte (unterminated string) and just reads off into the abyss.
If you used *pointer
, you would actually be dereferencing the pointer and getting the char
at the address the pointer points to.
The signature of strcpy is
char * strcpy ( char * destination, const char * source );
You are sending in pointer which is char*, and line which is also char*. Thus you are matching the signature exactly as expected. Sending in *pointer or *line would be sending 'the values these pointers point to' - which would be wrong.
scrcpy takes one pointer, and writes the contents it is pointing to to the location pointed by the another pointer. It is like rewriting cell contents in the table. You don't necessarily have to cut and paste a part of the table, you can rewrite the numbers in it. In that case pointer is just a hint which cells you have to touch.
Look at the declaration of strpcy().
char *strcpy(
char *strDestination,
const char *strSource
);
You need to pass a pointer. So you don't dereference pointer and line. Because that would pass a char.
The *
is inside strcpy
.
Applying the *
operator is called dereferencing, and is exactly the same as applying the [0]
.
strlen
and strcpy
need to know where the strings start so that they can access all of their elements, not just the first.
The type of pointer
is char *
while the type of *pointer
is char
, meaning a single character with no concept of neighboring characters.
By writing *pointer
, you obtain the character that it points to (which happens to be the first character of the string that pointer
represents). Passing it to strcpy
involves creating a copy of that character. It's impossible for strcpy
to know where it should be writing, unless you give it a pointer to that data.
In a similar fashion, by providing *line
you're only giving strcpy
a copy of the first character of your string.
So, you're basically saying:
I have two strings. I'm not giving them to you. The first letter of one is C, the first letter of the other is µ. Copy the contents of the first to the second
I see why you expect to pass *pointer
and *line
to strcpy
. But remember that pointer
points to the location in memory where the content is stored and where there is strlen(line)+1
bytes of memory is reserved and allocated. Thus what strcpy
is exactly doing is to copy strlen(line)
bytes of memory starting from the address line
into corresponding locations, starting from the address of pointer
. If you pass *pointer
and *line
, strcpy
will have access to only the first char
and not the rest of strlen(line)-1
. Hope that clarifies your confusion about the pointers and why we need to pass pointers to strcpy
.
Your basic understanding of strcpy
is correct. The function indeed copies the contents of line
over the contents of pointer
. However, you have to pass pointers to the function and not the data itself. This is done for several reasons.
First, the data that is being copied is a string (that is, an array) and not a regular variable. When passing an array to a function, you can't cram the entire array into a single function argument so instead you have to pass a pointer to the beginning of the array. This is a limitation of array passing in C and is not specific to strcpy
.
Also, passing data to a function provides the function with a copy of the variable's content. If you directly passed data (or de-referenced pointers) to strcpy
, the function would be working with copies and not the original data. It would be unable to write data to the original string.
Essentially, by handing pointers to strcpy
you are telling it the location of the source data and of the destination. The function handles all of the de-referencing internally. In human language, the call to strcpy
can be thought of as "take the string that starts at memory address line
and write a copy it starting at memory address pointer
". To communicate memory addresses, you use pointers.
Consider the strcpy code as:
char * strcpy(char * dst, char* src)
{
int i = 0 ;
for (;dst[i]=source[i++];);
return dst ;
}
\0(NULL) is the end of both the string and the for loop.
Your function is basically what strdup
does. The function is defined on many platform, if it isn't you can define this way:
char * my_strdup(const char* s)
{
size_t len = strlen(s);
char *r = malloc(len+1);
return r ? memcpy(r, s, len+1) : NULL;
}
memcpy is usually faster than strcpy for longer strings.
精彩评论