简体   繁体   中英

Arrays are passed by reference, but what happens if I only pass the value of an array which is not stored in memory?

I have this small program designed with the purpose of sorting all the character in C string in alphabetical order.

#include <stdio.h>
#include <string.h>

void SortLettersInString(char A[]);
int getSizeOfString(char A[]);

int main()
{
    char str[]="sbcdhiksjaghgfhsghjawyeqsadfsazxx";
    //THIS WORKS:
    SortLettersInString(str);

    //THIS CRASHES THE PROGRAM:
    //SortLettersInString("AAACBSVSFSA"); 
    scanf("%d");
    return 0;
}

void SortLettersInString(char A[])
{
    printf("Original string: %s\n",A);
    int sizeOfA = getSizeOfString(A);
    printf("Size of string: %d\n", sizeOfA);
    int i,j;
    for(i=0;i<sizeOfA;i++)
    {
        for(j=0;j<sizeOfA;j++)
        {
            if(A[i]<A[j])
            {
                //INTERCHANGING THE VALUES WITHOUT AUXILIARITY
                A[i]=A[i]^A[j];
                A[j]=A[i]^A[j];
                A[i]=A[i]^A[j];
            }
        }
    }
    //PRINT THE SORTED STRING:
    printf("Sorted string: %s\n", A);
}

int getSizeOfString(char A[])
{
    int i=0;
    while(A[i]!='\0')
    {
        i++;
    }
    return i;
}

My question is this: I know that arrays can be passed only by reference, so in my second call to the function SortLettersInString("AAACBSVSFSA") , I am passing the value of char array to this function, when I try to print the value of that array inside the function it prints it correctly. But why it does that, because there is no memory location reserved for that value. Also when the function reaches the point of interchanging values, it crashes. So what am I missing?

SortLettersInString("AAACBSVSFSA"); 

It is in memory. String literals don't exist in the ether, they are part of your programs' static memory, and you can pass their addresses to functions. It just so happens that this is not memory your program is allowed to modify, and if it attempts to modify it, the behavior of your program is undefined.

It should be noted, that in C++ the string literal is of the type const char[12] (which is much more const correct), and your program will not compile (so the C++ tag is dubious).


The reason this work:

char str[]="sbcdhiksjaghgfhsghjawyeqsadfsazxx";
//THIS WORKS:
SortLettersInString(str);

Is because something entirely different happens here. You define a local array with automatic storage, and you initialize its elements by copying the literal. Modifying your local variable is perfectly fine and well defined, it's not a const variable at all.

 void SortLettersInString(char A[]); 

This is not a reference . References only exist in C++, and there can be no references to arrays of unknown size; the code would look like this if A was a reference:

void SortLettersInString(char (&A)[100])

What you have here instead is a function taking a pointer to a modifiable (ie non- const ) char object. The [] syntax is merely a hint that the object may be the beginning of an entire array of modifiable char objects; it's not otherwise relevant or different from a char* A .

In any case, the function does use the non- const liberty you've granted it to modify the object(s), with code like: A[i]=A[i]^A[j]; .

So far, so good.

 char str[]="sbcdhiksjaghgfhsghjawyeqsadfsazxx"; 

This is like writing int x[] = { 1, 2, 3 }; . You can modify the three elements of the array, but you can of course not modify the numbers one, two and three themselves . The array elements are just modifiable copies of unmodifiable literals.

 //THIS WORKS: SortLettersInString(str); 

A string literal like "sbcdhiksjaghgfhsghjawyeqsadfsazxx" is just like an array of integer literals 1 , 2 and 3 . The literal itself cannot be modified, but the literal can be used to create modifiable copies. Your str[] is an array of modifiable char objects copied from the literal's unmodifiable char objects.

 //THIS CRASHES THE PROGRAM: //SortLettersInString("AAACBSVSFSA"); 

Depending on what language, compiler and compiler settings you use, this shouldn't even compile. If it does, it's undefined behaviour . You pass the unmodifiable literal directly to the function. The function tries to modify something which shouldn't be modified.

Crashing is one possible result of undefined behaviour.

What you are doing here is quite comparable to this:

void changeToTwo(int* x)
{
    *x = 2;
}

int main()
{
  changeToTwo(&1); // will not compile
  int one = 1;
  changeToTwo(&one); // will compile and work fine
}

A good practical reason for why it's a bad idea to try and modify string literals is that compilers are allowed to perform an optimisation called string-literal pooling , which allows identical string literals to share the same memory area.

these lines:

//THIS CRASHES THE PROGRAM:
//SortLettersInString("AAACBSVSFSA"); 

crashes the program because the literal is in read-only-memory. Cannot write to read-only-memory so a seg fault event is raised.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM