Why does function call change value of string in main function? - arrays

In the code, I wanted to reverse the string.
However, the function call changed the value of string A in the main function as well (The function is correct but I don't know why the function is changing the actual value of the string in the main function)
How could I reverse the string in revstr without modifying A from main?
#include<stdio.h>
#include<string.h>
void revstr(char A[], int l);
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr(A,l);
printf("%s", A);
return 0;
}
void revstr(char A[], int l){
int x=0,y,temp;
y=l-1;
while(x<y){
temp=A[x];
A[x]=A[y];
A[y]=temp;
x++;
y--;
}
printf("%s", A);
}

You are passing the array to the function call, (i.e., the pointer to the first element of the array), and from the called function, you're actually changing the contents of the memory locations.
The changes to these memory locations are not of a copy of the original array, rather taking place in the actual array itself. So, the changes made from the called function are reflecting in the caller function also. The actual array itself is getting modified, so when you try to print the array in the main() function, it already has it's contents modified, and that modified content is getting printed.
You need to keep a copy of the original array in the caller, if you want to refer the unmodified version later.

Be aware that what You are calling a string, really is an array of characters. As a consequence in the function You are not actually passing a string, but the location in memory (a pointer) of the first element of the char array.
So whats being manipulated in the function is whatever is stored at that specific location.
One way to work around this would be to pass an additional, empty array to the function in which the reversed string is stored.

When a function is called the arguments are evaluated and each parameter is assigned the value of the corresponding argument.
For example you can imagine the definition if the function revstr and its call in main the following way (for clarity I renamed function parameters like F_A and F_l)
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr(A,l);
//...
void revstr( /*char F_A[], int F_l */ )
{
char F_A[] = A;
int F_l = l;
//...
That is the function parameters are initialized by the values of the argument expressions.
But here is a problem. In this declaration
char F_A[] = A;
we are trying to initialize an array with an array designator something like
char A[] = "Hello";
char F_A[] = A;
Such an initialization is incorrect. You may initialize a character array either with a string literal or with a braced list of initializers.
So how is this problem resolved in C?
For starters the compiler adjusts function parameters that have array types to pointers to array element types. Thus this function declaration
void revstr(char A[], int l);
is adjusted by the compiler to the declaration
void revstr(char *A, int l);
and the both declarations declare the same one function. You may include the both declarations of the function in your program though the compiler can issue a message that there are redundant function declarations.
On the other hand, when an array is used as an argument expression it is also implicitly converted to pointer to its first element.
So in fact you have
void revstr( char *A, int l );
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr( &A[0], l );
//...
So within the function you are dealing with a pointer that points to the memory extent where the elements of the array A declared in main are situated. Using this pointer you are changing these elements that is the original array declared in main.
In fact the elements of the array A is passed to the function through a pointer to them. Such passing objects through pointers to them in C is called passing by reference. Using the pointers you have a direct access to the objects pointed to by the pointers.
Pay attention that that it is better to declare and define the function revstr the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
char * revstr( char *s, size_t n )
{
if ( n != 0 )
{
for ( size_t i = 0; i < --n; i++ )
{
char c = s[i];
s[i] = s[n];
s[n] = c;
}
}
return s;
}
int main(void)
{
char s[20];
scanf( "%19s", s );
size_t n = strlen( s );
puts( revstr( s, n ) );
return 0;
}
The program output might look like
Stackoverflow
wolfrevokcatS
That is the second parameter of the function revstr shall have the type size_t instead of the type int because size_t is the return type of the function strlen.
The function should return the pointer to the first character of the reversed array.

Related

Passing a pointer as a shorter array

Will this code give a Buffer overflow crash?
#include <stdio.h>
void show(char text[2]) {
printf("%c%c\n", text[0], text[1]);
return;
}
int main() {
char *txt = "aabc";
show (txt);
return 0;
}
I mean txt has 4 characters (plus '\0'), while text has only 2.
Arrays are passed in C by reference, this means when a function accepts an array as an argument it does not get a copy of that array, but rather a pointer to it.
So in your case char text[2] is not a new copy of txt in main, but rather a pointer to it. Thus you will not get an overflow as you are not trying to copy the contents of txt into char text[2], text just points to it.
For example the output of the following is 13
void test(char a[2]){
printf("%d", strlen(a));
}
int main(){
char* text = "Hello World!\n";
test(text);
}
You are mistaken.
The compiler implicitly adjusts a parameter declared like an array to pointer to the array element type.
So this declaration
void show(char text[2]);
is equivalent to the declaration
void show(char *text );
You could even declare the function like
void show(char text[1000]);
In any case the compiler will adjust it to the declaration
void show(char *text );
That is the function deals with a pointer to the first element of the array passed to the function as an argument or with the value of the passed pointer as an argument.
So neither overflow occurs. The string literal itself is not moved from one part of memory to another. It is the value of the pointer that is passed to the function.
It is your responsibility not to access the passed string beyond the allocated memory for it.

Pointers in functions and pointers in lists

When I was introduced to pointers, I was told that they are useful because they let us modify certain variables fed into functions that wouldn't normally be modifiable. For example:
void copy(int *p, int *s);
int main(){
int a = 4, b = 10, *p = &a, *s = &b;
copy(p, s);
}
void copy(int *p, int *s){
*s = *p;
*p = 0;
}
So at the end of this, "b" is equal to "a", and "a" is equal to 0, even though "a" and "b" wouldn't normally be modifiable.
When talking about lists and, specifically, adding an element to a list, I can use a function like this:
struct list{
int n;
struct list *next;
}
struct list *first = NULL;
int main(){
int n = 3;
first = add_to_list(first, n);
}
struct list *add_to_list(struct list *first, int n){
struct list *new_node;
new_node = malloc(sizeof(struct list));
if(new_node == NULL) exit(EXIT_FAILURE);
new_node->value = n;
new_node->next = first;
return new_node;
}
What concerns me specifically is why the function can't simply return a type void, and instead of writing "return new_node", I can't simply write "first = new_node". Because first is a pointer, if I modify it anywhere in my program the original pointer should be modified too, just like it happened in the first example I made, right?
Also, bit of an unrelated question, but if I've got a function like this:
void first_to_n(int a[], int n){
a[0] = n;
}
The first element of the original vector a, which lets say is declared in main, gets also modified, right? Because vectors can be considered as pointers
Lets say we have something like the following code
void funcA(int x)
{
x = 0;
}
void funcB(int *y)
{
y = NULL;
}
int main(void)
{
int a = 10;
int *b = &a;
funcA(a);
funcB(b);
}
What happens when funcA is called is that the value of a is copied into the separate variable x inside the function. When the call is being made there are two copies of the value 10 stored in to different places. When the assignment x = 0 is done inside the function, only the local variable x is modified.
For funcB just the same happens. The value of the variable b is copied into the separate variable y in the function. That means there are two separate and distinct variable pointing to the same location. But once the assignment y = NULL is done, that's no longer true. The variable y is no longer pointing to the same location, but in the main function b is unmodifed since only a copy of the value was passed to the function.
If we now take a slightly different example
void func(int *x, int **y)
{
*y = x;
}
int main(void)
{
int a = 10;
int b = 20;
int *c = &a; // Make c point to the variable a
func(&b, &c);
}
After the function is called, then c does no longer point to a, it points to b. That's because for the second argument the value we pass is &c which is a pointer to the variable c. Inside the function we can then use the dereference operator to access what y is pointing to (which will be the variable c in the main function).
When I was introduced to pointers, I was told that they are useful because they let us modify certain variables fed into functions that wouldn't normally be modifiable.
Among other things, like creating non-trivial data structures and to avoid copies.
Because first is a pointer, if I modify it anywhere in my program the original pointer should be modified too, just like it happened in the first example I made, right?
first (the parameter) is a copy of first (the global). Therefore, first = new_node would only modify your pointer, not the global one.
This is more clear in your first example:
void copy(int *p, int *s){
*s = *p;
*p = 0;
}
If you were doing p = 0;, for instance, you would only modify the pointer, not the value pointed to.
The first element of the original vector a, which lets say is declared in main, gets also modified, right? Because vectors can be considered as pointers
That is not a "vector" (array), it is a pointer even if it looks like an array. It is a big gotcha of C.
But, indeed, a[0] = 0; is modifying the first value (in main) pointed by the parameter.
What concerns me specifically is why the function can't simply return
a type void, and instead of writing "return new_node", I can't simply
write "first = new_node".
As the other answers explain, you can't due to first being a 'copy' of the pointer outside the function. If however you were to instead change the function such that you passed a 'pointer to the pointer' rather that just the 'pointer', then you could change the external value, which is what's going on the in the 'copy' function.
This uses a pointer to a literal string.
The pointer is pass to modifypointer() where it is modified to point to another literal string. The new literal string is printed in the function, but main() still prints the original.
The pointer is passed as a pointer to itself in modifypointertopointer() where it is dereferenced to point to another literal string. Now the function prints the new literal string and main() also prints the new literal string.
In your last example, first = new_node; could be used except the function declares a shadow variable first and the global first is no longer in the scope of the function.
#include <stdio.h>
void modifypointer( char *mod) {
mod = "modify pointer";
printf ( "%s\n", mod);
}
void modifypointertopointer( char **ptrmod) {
*ptrmod = "modify pointer to pointer";
printf ( "%s\n", *ptrmod);
}
int main( void) {
char *text = "original";
printf ( "%s\n", text);
modifypointer ( text);
printf ( "%s\n", text);
modifypointertopointer ( &text);
printf ( "%s\n", text);
return 0;
}

assign dynamic array in a function and send it back to the caller in C

I have been using java for long time but for some reason I need to use C (ANSI C not C++) to write a simple code. I need to pass the pointer from outside to a function, allocate some memory to the pointer and assign some values also before the function return. I have my code like
#include <stdio.h>
#include <stdlib.h>
void test(int *a)
{
int n=3;
// I have to call another function t determine the size of the array
n = estimatesize(); // n >=3
// I tried fix size n=10 also
a = (int*)malloc(n*sizeof(int));
a[0] = 1;
a[1] = 2;
a[2] = 3;
}
void main(void)
{
int *s=NULL;
test(s);
printf("%d %d %d", s[0], s[1], s[2]);
}
I don't know why the code crashes. I thought at the beginning it is estimatesize() return wrong number but even I fix n to 10, the error still there. So I cannot pass a pointer to a function for memory allocation? If so, how can I dynamically create memory inside a function and pass it out? I know it may be a safe problem in this way but I just want to know if it is possible and how to do that. Thanks.
There are two solutions to this: Either return the pointer from the function, or pass the argument by reference.
For the first one, you simply don't take any arguments, instead you return the pointer:
int *test(void)
{
int *a = malloc(...);
...
return a;
}
int main(void)
{
int *s = test();
...
}
For the second one, you need to pass the address of the pointer, in other words a pointer to the pointer, using the address-of operator &:
void test(int **a)
{
*a = malloc(sizeof(int) * 3);
for (int i = 0; i < 3; ++i)
(*a)[i] = i;
}
int main(void)
{
int *s;
test(&s);
...
}
The reason it doesn't work now, is because the pointer (s in main) is passed by copying it. So the function test have a local copy, whose scope is only in the test function. Any changes to a in the test function will be lost once the function returns. And as s is copied for the argument, that means that s in main never actually changes value, it's still NULL after the function call.

How Do you pass a pointer-to-an-array to a function?

How do you pass an array to a function where that function can edit it's contents?
like when doing
function(int *x)
{*x = 10;}
main()
{int x;
function(&x);}
how could i do the same using a character array?
whenever I do
function(char *array[], int *num)
{ int x = *num;
*array[x] = 'A'; }
main()
{ char this[5] = "00000"; //not a string
int x = 3;
function(&this, &x); }
DEV C++ says
[Warning] passing arg 1 of `function' from incompatible pointer type
obviously I did something wrong, so please tell me how to fix that. Thanks :D
You should write:
void function(char array[], int *num)
{
int x = *num;
array[x] = 'A';
}
void main()
{
char my_array[5] = "00000";
int x = 3;
function(my_array, &x);
}
Notation char *array[] is an array of pointers that you do not need here.
When you pass an array somewhere, you should not take its address. Arrays are adjusted to pointers by default.
EDIT:
Function prototypes:
void function(char array[], int *num);
void function(char *array, int *num);
are absolutely identical. There is no even minor difference between them.
Since arrays can only be passed by address, you don't really want a char * array here, just a char array:
rettype function(char *array, int *num)
{
array[*num] = 'A';
}
int main()
{
char arr[] = "1234567890";
int i = 2;
function(arr, &i);
}
In C, array names "devolve" to a pointer to the head of the array, by passing "&array", you're passing a pointer to a pointer to the head of the array, thus the warning.
char array[512];
myfunc(array, foo);
is the proper way to do what you want.
Actually you have taken one dimension array. So you can define function in two ways...
(i)
function(char array[], int *num)
{ int x = *num;
*array[x] = 'A'; }
main()
{ char this[5] = "00000"; //not a string
int x = 3;
function(this, &x); }
and
(ii)
function(char *array, int *num)
{ int x = *num;
*array[x] = 'A'; }
main()
{ char this[5] = "00000"; //not a string
int x = 3;
function(this, &x); }
But in your function definition, you wrote *array[] as argument which means the array is two dimensional array. So you should declare array as two dimensional array.
function(char *array[], int *num)
{ int x = *num;
//implement your code }
main()
{ char this[5][10];
// you can initialize this array.
int x = 3;
function(this, &x); }
I think it will be helpful to you.
Okay, the first thing to remember is that there's no such thing as a pointer "to an array" although you'll hear that said fairly often. It's sloppy.
(As pointed out below, the terminology "pointer to an array" does strictly have a meaning -- but I maintain that you've been confused by it. What really happens is that every pointer contains an address. Depending on the declaration, the compiler can identify if it's being used correctly in context, and that's what your error message is really telling you: what you declared in the function is a pointer to an array of chars, which is to say the same thing as a char **, instead of a char *, which is what you're passing. But char *, or char **, or char ******, the important point is that you're making it too complex -- you already have the address you need identified by the array name.)
Pointers is pointers, they're addresses.
An array in C is simply an allocated chunk of memory, and it's name represents the address of the first element. So
char a[42];
is a block of memory 42 char's long, and a is its address.
You could rewrite your second function as
void foo(char* a, int num){ // (3)
// notice that you don't need the word function and
// for lots of reasons I wouldn't use it as a function name.
a[num] = 'A'; // (4)
}
int main(){
// Sadly "00000" IS a string no matter what your comment
// says. Use an array initializer instead.
char arry[5] = {'0','0','0','0','0' } ; // (1)
foo(arry,3); // (2)
}
This does what I believe your code means to do. Note that
(1) Since "00000" really is a string, it's actually creating an array 6 elements long which could have been initialized with the array initializer
{'0','0','0','0','0', 0 }
(2) The array (which I named 'arry' instead of 'this' since 'this' is often a keyword in C-like languages, why risk confusion?) is already an address (but not a pointer. It can be on the right-hand side of an assignment to a pointer, but not on the left hand side.)
So when I call
foo(arry,3);
I'm calling foo with the address of the first element of arry, and the number 3 (you don't need to declare a variable for that.)
Now, I could have also written it as
foo(&arry[0],3);
You would read that as "find the 0-th element of arry, take its address." It is an identity in C that for any array
char c[len];
the expression c and &c[0] refer to the same address.
(3) that could also be defined as foo(char arry[], int num). Those are equivalent.
(4) and when you refer to a[num] you're referring directly to the num-th element of the memory pointed to by a, which is at the address of the start of the array arry. You don't need all that dereferencing.
Don't be disturbed that this is a little hard to follow -- it's tough for everyone when they start C.
Firstly dont use this as a variable name, its a C++ keyword. Sorry didnt realise it was a C question.
main()
{
char foo[5] = "00000"; //not a string
int x = 3;
function(foo, &x);
}
You dont take the memory address of foo. foo when used in a pointer-accepting context degrades into a pointer to the first element. *foo is the same as foo[0] which is the same as *(foo + 0)
like wise foo[3] is the same as *(foo + 3) (the compiler takes care of multiplying the element size).

Is it possible to still address the individual elements of an array via a pointer?

I am trying to write a program that will mutliply two numbers, but output the result in binary, showing the calculation (i.e. shifting the rows). I'm storing the binary numbers as an array of 32 characters, and each element is either 1 or 0.
I have a function that will convert decimal to binary character array, but then my array only exists within the function, but I need to use the array within another function and also within main. I was thinking it might be possible to use pointers to change the value of the array in main from within my converter function, so then the array will exist in main and can be used in other functions. Is this possible?
I've declared two pointers to character arrays:
char (*binOne)[32];
char (*binTwo)[32];
if I pass the pointer as a parameter to the function, can I still access each element? Sorry if I'm not making much sense here.
In C, most of the time array behaves like pointer to its first element, so what you probably want to do is:
void foo(char* arr){
//some stuff, for example change 21-th element of array to be x
arr[20] = 'x';
}
int main(){
char binOne[32];
char binTwo[32];
// change array binOne
binOne[20] = 'a';
foo(binOne);
// now binOne[20] = 'x'
foo(binTwo);
// now binTwo[20] = 'x'
}
A continuation of what I added as a comment:
In C, if you want to modify/return an array, you'll do that by passing a pointer to it as an argument. For example:
int toBinary(char *buff, int num) { /* convert the int, return 1 on success */ }
...
char buff[32];
toBinary(buff, 9001);
In C, an array's name is it's address, it's the address of the first element:
buff == &buff == &buff[0]
Yes, this is possible. But you only need a pointer to the array not an array of pointers.
You need to prototype like
e.g.
void int_to_arr(int n, char *arr);
void arr_to_int(int *n, char *arr);
in main(){
char *binarr = calloc(32, sizeof(char));
int n = 42;
int_to_arr(n, binarr);
}
void int_to_arr(int n, char *arr)
{
//do you conversion
//access array with
// arr[i]
}
void arr_to_int(int *n, char *arr)
{
//do you conversion
//access array with
// *n = result;
}

Resources