Am I passing a copy of my char array or pointer?

I studied C, and I decided to practice my knowledge by creating some string management functions. I wrote a string reverse function and a main function that asks for user input, sends it via stringreverse () and prints the results.

Basically, I just want to understand how my function works. When I call this "tempstr" as the first parameter, is this understood as the address of the first element in the array? Basically, like say & tempstr [0], right?

I think the answer to this question will tell me: will there be any difference if I assigned a char * pointer to my tempstr array and then sent it to stringreverse () as the first parameter, compared to how I do it Now? I want to know if I am sending a duplicate of the tempstr array or 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; } 

Thank you for your time. Any other criticisms would be helpful., Just a few weeks in programming: P

EDIT: Thanks to all the answers, I figured it out. Here's my solution for someone interested:

 #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]; } } 
+4
source share
5 answers

First, the detail:

 int main() { char* stringreverse(char* tempstr, char* returnptr); 

This prototype should go beyond main (), for example:

 char* stringreverse(char* tempstr, char* returnptr); int main() { 

As for your main question: the tempstr variable is char *, i.e. the address of the character. If you use C index notation, for example tempstr [i], this is essentially the same as * (tempstr + i). The same applies to revstr, except that in this case you are returning the address of the memory block that is about to be knocked down when the array it points to goes out of scope. You have the right idea, going to the address of some memory into which the return line is written, but you are not really copying the data into the memory pointed to by this block. In addition, the line:

 returnptr = &revstr[0]; 

Does not do what you think. You cannot assign a new returnptr pointer; if you really want to change returnptr, you will need to pass its address, so the parameter will be specified char ** returnptr. But don't do this: instead, create a block in your main () that will receive the return string and pass its address in the returnptr parameter. Then use this block, not the temporary one you are using now, in stringreverse ().

+1
source

When I call it with 'tempstr' as the first parameter, should this be understood as the address of the first element in the array? Basically, how to say &tempstr[0] , right?

 char tempstr[1024]; 

tempstr is an array of characters. When you pass the tempstr function to a function, it splits into a pointer pointing to the first tempstr element. So, its basically the same as sending &tempstr[0] .

Will there be any difference if I assigned a char * pointer to my tempstr array and sent it to stringreverse () as the first parameter, compared to how I'm doing it now?

No difference. You can do -

 char* pointer = tempstr ; // And can pass pointer 

 char *revstr = stringreverse(tempstr, revstr); 

The first expression of the right-hand side is evaluated, and the return value is assigned to revstr . But what is revstr that is transmitted. A program must allocate memory for it.

 char revstr[1024] ; char *retValue = stringreverse(tempstr, revstr) ; // ^^^^^^ changed to be different. 

Now, when passing tempstr and revstr they decompose into pointers pointing to their respective first indexes. In this case, why does this go wrong -

 revstr = stringreverse(tempstr, revstr) ; 

Just because arrays are not pointers . char * is different from char []. Hope this helps!

+1
source

Basically, I just want to understand how my function works.

One of the problems is that you are using revstr without initializing or allocating memory for it. This behavior is undefined, since you are writing to memory, not yours. It may work, but in fact, what you have is a mistake and may produce unexpected results at any time.

When I call it "tempstr" as the first parameter, should I understand it as the address of the first element of the array? Basically, like say & tempstr [0], right?

Yes. When arrays are passed as arguments to a function, they are treated like regular pointers pointing to the first element in the array. It makes no difference if you assigned &temp[0] to char* before passing it to stringreverser , because that is what the compiler does for you anyway.

The only time you see the difference between arrays and pointers passed to functions is in C ++ when you begin to learn patterns and specialized specialization. But this question is C, so I just thought I would drop it.

+1
source

In answer to your question about whether the function passed is an array or a pointer, the relevant part of the C99 standard (6.3.2.1/3) states:

Unless it is an operand of a sizeof operator or a unary operator, or is a string literal used to initialize an array, an expression that is of type type '' type is converted to an expression with a type pointer '' to indicate what points to the initial element of an array object and is not an lvalue.

So yes, besides introducing another explicit variable, the following two lines are equivalent:

 char x[] = "abc"; fn (x); char x[] = "abc"; char *px = &(x[0]); fn (px); 

As for criticism, I would like to raise the following.


While legal, I find it inappropriate to have function prototypes (e.g. stringreverse ) anywhere except at the file level. In fact, I prefer to order my functions so that they are usually not needed, making less space where you have to change it if you need to change the arguments or the type of the return value. This entails in this case placing stringreverse to main .


Never use gets in a real program. It is not protected against buffer overflows. At a minimum, use fgets , which can be protected, or use a decent input function, such as found here .


You cannot create a local variable in stringreverse and pass its address. This behavior is undefined. As soon as this function returns, this variable will disappear, and you will most likely point to everything that happens to replace it on the stack the next time the function is called.


There is no need to pass in the revstr variable. If it were a pointer with backup memory (i.e., space was allocated for it), that would be nice, but then there would be no need to return it. In this case, you would single out both subscribers:

 char tempstr[1024]; char revstr[1024]; stringreverse (tempstr, revstr); // Note no return value needed // since you're manipulating revstr directly. 

You should also avoid magic numbers such as 1024 . It is better to have lines like:

 #define BUFFSZ 1024 char tempstr[BUFFSZ]; 

so you only need to change it in one place if you ever need a new value (which becomes especially important if you have many 1024 numbers with different values ​​- global search and replacement will be your enemy in this case and not your friend) .


To make your function more adaptable, you might want to allow it to handle any length. You can do this by passing both buffers, or using malloc to dynamically allocate buffers for you, for example:

 char *reversestring (char *src) { char *dst = malloc (strlen (src) + 1); if (dst != NULL) { // copy characters in reverse order. } return dst; } 

It is the responsibility to free this memory from the caller, but it is a debilitating way to do something.


You should probably use one of the two canonical forms for main :

 int main (int argc, char *argv[]); int main (void); 

It is also a particularly bad idea to call main from anywhere. Although this might seem like a great way to get an infinite loop, it will almost certainly end up chewing on your stack space :-)


All in all, this is probably the function I originally wrote. This allows the user to fill in their own buffer if they want, or to indicate that they do not have them, in which case the following 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; } 
+1
source

In your stringreverse() function, you return the address of the local variable ( revstr ). This is undefined behavior , and it is very bad. Your program may be working right now, but in the future it will end unexpectedly for reasons that are not obvious.

You have two main options:

  • Have a stringreverse() memory allocation for the returned string and leave it to the caller to free it.
  • Ask the caller to allocate space for the returned string and tell stringreverse() where it is and how big it is.
0
source

Source: https://habr.com/ru/post/1344870/


All Articles