Pointer of Strings and Integers - c

I would like some help with pointer of strings and integers. If I intend to change the value of integers defined in the main function, it is necessary to pass the pointer of the variables otherwise nothing will be changed like: (a and b will swap to each other's original value)
void swapping(int *a,int *b){
int temp=0;
temp= *a;
*a=*b;
*b=temp;
}
int main(){
int a=1,b=2;
swapping(&a,&b);
printf("%d\n%d\n",a,b );
return 0;
}
However, when I continue on passing strings(char arrays), operations like this is feasible:
void split(char take1[],char take2[], char str[]){
int i=0,j=0,yes=0;
while(str[i]!='\0'){
if(str[i]=='*'){
yes=1;
i++;
}
if(yes==0){
take1[i]=str[i];
}
else if (yes!=0){
take2[j]=str[i];
j++;
}
i++;
}
}
int main(){
char taker1[30],taker2[30];
char str[30]="Hello*world";
split(taker1,taker2,str);
printf("%s\n%s\n",taker1,taker2) ;
return 0;
}
My shallow understanding is because functions that get called are temporarily stored in RAM, so the value reassigned in the function will be removed once the function call is finished. Thus, we need to change the value of pointer in the memory.
But I didn't get why there is no need to pass the pointer of the char arrays as in second example to the function(split()) to alter their values . Could someone please help to see why? Thanks!

(OP) But I didn't get why there is no need to pass the pointer of the char arrays as in second example to the function(split()) to alter their values .
With many operations1, arrays are converted to the pointer of the first element. That happened with
split(taker1,taker2,str);
Let's dig deeper.
The C standard library defines string
A string is a contiguous sequence of characters terminated by and including the first null character. C17dr § 7.1.1 1
char array str below contains a string.
char str[30]="Hello*world";
char arrays taker1, taker2 are uninitialized. They do not certainly contain a string.
char taker1[30],taker2[30];
(OP) I continue on passing strings(char arrays),
Not quite. Below, char array taker1 is converted to the address of the first element when passed to the function. Like-wise for taker2, str
split(taker1, taker2, str);
split() receives 3 pointers, even though it may look like arrays.
void split(char take1[],char take2[], char str[]){
// same as
void split(char *take1, char *take2, char *str) {
The body of split() then uses these pointers to manipulate data. Recall these pointers point to main's str[], taker1[], taker2[]. When splt() is done, printf("%s\n%s\n", taker1, taker2) ; shows the effect.
1 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. C17dr

char take[] is essentially the same as char *take. So you actually passing the pointer.
In char taker[30] case for example taker itself is a pointer and taker[n] is equivalent to *(taker + n).

EXPLANATION
This is because, in C, an array declaration decays to a pointer internally (Refer to the citation at the end for details). When you declare char a[], it is the same as declaring char* a. In both of these cases, a stores the memory address of the first element of the array. But, in the case of variables like plain integers or characters, such as int x = 10;, the variable x will actually store the value 10.
When you declare an array such as
char a[10];
the object designated by the expression a is an array (i.e., a contiguous block of memory large enough to hold 10 character values a.k.a string), and the type of the expression a is an "array of 10 character elements", or char[10]. The expression a is implicitly converted to char *, and its value is the address of the first element.
Thus, when you pass an array variable to a function, you are actually passing the memory address (or base address) of the array. And since you have written your function declaration as:
void split(char take1[],char take2[], char str[])
It is the same as writing:
void split(char *take1,char *take2, char *str)
And, in your function call which is:
split(taker1,taker2,str);
taker1, taker2 and str actually contain base addresses of the respective character arrays (i.e. string). So you don't explicitly have to mention the address_of operator (&) along with the array variables in the function call.
The code you have posted can also be written as follows:
void split(char *take1,char *take2, char *str){
int i=0,j=0,yes=0;
while(*(str+i) != '\0'){
if(*(str+i) == '*'){
yes=1;
i++;
}
if(yes==0){
*(take1+i) = *(str+i);
}
else if (yes!=0){
*(take2+i) = *(str+i);
j++;
}
i++;
}
}
int main(){
char taker1[30], taker2[30];
char str[30] = "Hello*world";
split(taker1, taker2, str);
printf("%s\n%s\n", taker1, taker2) ;
return 0;
}
Notice the interchanged array operator([]) and and dereference operator(*). Hint: Writing arr[5] is the same as *(arr + 5).
LONG STORY SHORT:
In C, arrays are passed by reference. Normal variables are passed by value.
Array variables can be treated as pointers.
You ought to normally skip the & with array variables in function calls.
BONUS
The aforementioned reason is also why we don't use & in scanf() for string variables (with %s format specifier), i.e.,
char str[10];
scanf("%s", str);
But in the case of integers or other primaries:
int num;
scanf("%d", &num);
Also, you will get a better understanding of the concepts involved after going through dynamic memory allocation in C.
CITATION
Here's the exact language from the C standard (n1256):
6.3.2.1 Lvalues, arrays, and function designators ... 3 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. If the array object has register storage
class, the behavior is undefined.

Related

Reference to Array vs reference to array pointer

void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main(){
char array[10] = {'j','o','h','n'};
char * bla = array;
check(&bla);
check(&array);
}
Output:
word is john
RUN FINISHED; Segmentation fault; core dumped;
First one works, but second not. I don't understand why this happens.
The problem is, when we do &array, we are getting a char (*)[10] from an char [10], instead of a char **.
Before we do our experiment, I will emphasize that, when we pass an array as an argument to a function, C actually casts the array to a pointer. The big bucket of data is not copied.
Thus, int main(int argc, char **argv) is identical to int main(int argc, char *argv[]) in C.
This made it available for us to print the address of an array with a simple printf.
Let's do the experiment:
char array[] = "john";
printf("array: %p\n", array);
printf("&array: %p\n", &array);
// Output:
array: 0x7fff924eaae0
&array: 0x7fff924eaae0
After knowing this, let's dig into your code:
char array[10] = "john";
char *bla = array;
check(&bla);
check(&array);
bla is char *, and &bla is char **.
However, array is char [10], and &array is char (*)[10] instead of char **.
So when you pass &array as an argument, char (*)[10] acts like a char * when passing as an argument, as is said above.
Therefore **(char **) &bla == 'j' while *(char *) &array == 'j'. Do some simple experiments and you will prove it.
And you are casting void *elemAddr to a char ** and try to deference it. This will only work with &bla since it is char **. &array will cause a segfault because "john" is interpreted as an address as you do the cast.
For check(&bla); you are sending pointer to pointer
void check(void* elemAddr){
char* word = *((char**)elemAddr); // works fine for pointer to pointer
printf("word is %s\n",word);
}
This is working fine.
But, for check(&array); you are passing pointer only
void check(void* elemAddr){
char* word = *((char**)elemAddr); // This is not working for pointer
char* word = *(char (*)[10])(elemAddr); // Try this for [check(&array);]
printf("word is %s\n",word);
}
Full Code--
Code for check(array);:
void check(void* elemAddr){
char* word = *(char (*)[10])(elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
check((char*)array);
return 0;
}
Code for check(&bla);:
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
char* bla = array;
check(&bla);
return 0;
}
The C specification says that array and &array are the same pointer address.
Using the name of an array when passing an array to a function will automatically convert the argument to a pointer per the C specification (emphasis mine).
6.3.2.1-4
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. If the array object
has register storage class, the behavior is undefined.
So calling func(array) will cause a pointer to char[] to be passed to the function. But there is a special case for using the address-of operator on an array. Since array has type "array of type" it falls into the 'Otherwise' category of the specification (emphasis mine).
6.5.3.2-3
The unary & operator yields the address of its operand. If the operand
has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the
operand is the result of a unary * operator, neither that operator nor
the & operator is evaluated and the result is as if both were omitted,
except that the constraints on the operators still apply and the
result is not an lvalue. Similarly, if the operand is the result of a
[] operator, neither the & operator nor the unary * that is implied by
the [] is evaluated and the result is as if the & operator were
removed and the [] operator were changed to a + operator. Otherwise,
the result is a pointer to the object or function designated by its
operand
So calling func(&array) will still cause a single pointer to be passed to the function just like calling func(array) does since both array and &array are the same pointer value.
Common-sense would lead you to believe that &array is a double pointer to the first element of the array because using the & operator typically behaves that way. But arrays are different. So when you de-reference the passed array pointer as a double pointer to the array you get a Segmentation fault.
This is not a direct answer to your question, but it might be helpful to you in the future.
Arrays are not pointers:
type arr[10]:
An amount of sizeof(type)*10 bytes is used
The values of arr and &arr are necessarily identical
arr points to a valid memory address, but cannot be set to point to another memory address
type* ptr = arr:
An additional amount of sizeof(type*) bytes is used
The values of ptr and &ptr are typically different, unless you set ptr = (type*)&ptr
ptr can be set to point to both valid and invalid memory addresses, as many times as you will
As with regards to your question: &bla != bla == array == &array, and therefore &bla != &array.
One problem is that your char array is NOT NECESSARILY going to be null-terminated. Since array is an automatic variable that is allocated locally on the stack, it is not guaranteed to be zeroed-out memory. So, even though you are initializing the first 4 chars, the latter 6 are left undefined.
However ...
The simple answer to your question is that &bla != &array so your check() function is assuming it will find null-terminated character arrays at 2 different addresses.
The following equations are true:
array == &array // while not the same types exactly, these are equivalent pointers
array == bla
&array == bla
*bla == array[0]
&bla is never going to equal anything you want because that syntax references the address of the bla variable on the local stack and has nothing to do with its value (or what it points to).
Hope that helps.

Alternate pgm for the given pgm without using function

#include <stdio.h>
void lower_string(char*);
int main()
{
char string[100];
printf("Enter a string to convert it into lower case\n");
gets(string);
lower_string(string);
printf("Entered string in lower case is \"%s\"\n", string);
return 0;
}
void lower_string(char *string)
{
while(*string)
{
if ( *string >= 'A' && *string <= 'Z' )
{
*string = *string + 32;
}
string++;
}
}
In this program what if i replace *string with string[]?
can anyone help me in writing the above program without using any function?
And please explain what does this mean while(*str) ?
void lower_string(char *string);
and
void lower_string(char string[]);
are equivalent in C. A parameter of type char [] is adjusted to type char *.
Of course when string is the operand of the * operator like in:
while (*string)
then you cannot change it to string[] as * here is the indirection operator and not a part of a type name.
There is no difference between the two, because when an array is passed to a function, it decays adjusts to a pointer.
I wouldn't write such code and then tag it C++, because string is a standard library class name.
C-FAQ: Q-6.4:
Since arrays decay immediately into pointers, an array is never actually passed to a function. You can pretend that a function receives an array as a parameter, and illustrate it by declaring the corresponding parameter as an array:
void f(char a[])
{ ... }
Interpreted literally, this declaration would have no use, so the compiler turns around and pretends that you'd written a pointer declaration, since that's what the function will in fact receive:
void f(char *a)
{ ... }
There's nothing particularly wrong with talking about a function as if it ``receives'' an array, if the function is traditionally used to operate on arrays, or if the parameter is naturally treated within the function as an array.
This conversion of array-like declarators into pointers holds only within function formal parameter declarations, nowhere else.
The symbol [] is basically equivalent to * in some way.
You can accept char[] and still treat it as a pointer with * and you can accept a char* as a parameter and access it with [] as a regular array - it's exactly the same.
You're always getting a pointer to that spot in memory, when it's an array defined with [] though, the pointer will be constant (can't deference it, only access where it's pointing to).
When you're declaring an array using char str[100]; you're actually declaring a const char* named str and pointing to a memory area in the stack.
They are pretty much the same thing. For example,
sz[x];
is short for
*(sz + x);
However, when you write char *sz;, all yau are getting is a pointer. Wen you write char sz[size];, you are getting an array also. See haccks' answer.

Doubts on char* list[] with return length C and C++

If I wrote it in the following way, I return the result as 1. Don't understand why? The expected answer is 5.
int main()
{
const char* list_of_filename[] = {"One","Two","Three","Four","Five"};
printf("%d", countFiles(list_of_filename));
return 0;
}
int countFiles(const char* list_of_filename[])
{
return sizeof(list_of_filename) / sizeof(list_of_filename[0]);
}
sizeof for an array only works in the scope where you declare the array.
const char* list_of_filename[] = {"One","Two","Three","Four","Five"};
printf("%d", sizeof(list_of_filenames) / sizeof(list_of_filenames[0]));
In C, you can not pass arrays. So:
int countFiles(const char* list_of_filename[])
is exactly the same as:
int countFiles(const char **list_of_filename)
So you're comparing the sizes of two pointers. The size of const char * and const char ** are the same on your system.
This answer (by Michael Burr, but originally from Chromium) provides a macro that does the array size calculation, and errors on some invalid constructs like this (but not this one)
As a function argument,
const char* list_of_filename[]
actually means:
const char** list_of_filename.
Therefore what you're in fact calculating is:
sizeof(char**) / sizeof(char*)
char** and char* are both just pointers, and since all pointers generally have the same size (at least in this case, for you, these two do):
x / x
= 1
EDIT: When passing an array to a function in C, you'll generally either want to pass the size of the array or terminate your array with a specific value in order to be able to determine the length of it.
From the C standard (C11 6.3.2.1 Lvalues, arrays, and function designators, para 3):
Except when it is the operand of the sizeof operator, the _Alignof 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.
In other words, when you pass that array to a function, it becomes a pointer to the first element of the array and its size is therefore the size of a pointer.
If you want to treat it as an array within the function, you need to explicitly pass in the size information with something like:
void printArray (int *arr, size_t sz) {
for (size_t i = 0; i < sz; i++)
print ("%d ", arr[i]);
puts ("");
}
:
int xyzzy[] = {3,1,3,1,5,9,2,6,5,3,5,8,9};
printArray (xyzzy, sizeof (xyzzy) / sizeof (*xyzzy));
C Arrays and Pointers are not the same!
One of the first things that novice C programmers often hear is that "arrays are the same as pointers.". Unfortunately, this is a dangerous half-truth. The ANSI C Standard paragraph 6.5.4.2 recommends that you
Note the distinction between the declarations:
extern int *x;
extern int y[];
The first declares x to be a pointer to int; the second
declares y to be an array of int of unspecified size (an incomplete
type), the storage for which is defined elsewhere.
The standard doesn't go into the matter in any greater detail than that.
So when you try to get sizeof from array it returns size of the whole array in bytes (sum of objects' sizes), when you try to get sizeof of pointer - it returns size of pointer in bytes. Size of pointers it is always constant value on one platform. Generally it is 4 or 8 bytes.
Remember this :)

referencing an index value of a character in a pointer string in c

Suppose I have something like this
int strLen;
printf("Please enter a number: ");
scanf("%d", &strLen);
char *myString;
myString = (char*) malloc(strLen*sizeof(char));
then you fill string with something like "Hello World!" but now I want to just print out "World!" Since my string is just a pointer reference, I can't call it out by indexes ie.
for(int i=6;i<strLen;i++)
{
printf("%s", myString[i]);
}
// THIS IS AN INCORRECT WAY TO DO THIS
How could I refer to a specific character or even pass the array onto another function of the program if all I have is the array base pointer? Can I ever get the full functionality as if I declared it as a static array before compile time?
How could I refer to a specific character or even pass the array onto another function of the program if all I have is the array base pointer?
Several things to remember:
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be replaced with ("decay to") an expression of type "pointer to T" whose value is the address of the first element of the array;
In the context of a function parameter declaration, T a[N] and T a[] are identical to T *a (IOW, a will be declared as a pointer to T, not an array of T - note that this is only true for function parameter declarations);
The subscript operation a[i] is defined as *(a + i) - start with a base address specified by the pointer expression a, offset by i elements (not bytes), and dereference the result;
In C, you do not need to cast the result of malloc (or calloc or realloc), since it returns a value of type void *, which may be assigned to any other object pointer type. Adding the cast may suppress a useful diagnostic if you forget to include stdlib.h or otherwise don't have a prototype in scope. Note that this is not true for C++ - a cast is required there, but if you're writing C++ you should be using new instead of malloc anyway.
This is a long-winded way of saying that, in many contexts, array expressions and pointer expressions can be treated the same way. Taking printf as an example:
int main(void)
{
char foo[] = "This is a test";
char *bar = foo;
printf("%s\n", foo);
printf("%s\n", &foo[0]);
printf("%s\n", bar);
return 0;
}
printf expects the argument corresponding to %s to have type char *, or "pointer to char", not "array of char". The three printf calls above are all equivalent. In the first call, foo is an array expression with type "15-element array of char". By the first rule mentioned above, it will be replaced with an expression of type "pointer to char" whose value is the address of the first element. The second and third calls pass the pointer value directly, just using different expressions to accomplish the same effect.
As far as printf is concerned, all three expressions yield the same result -- the address of the first element of a sequence of char values, terminated by 0.
What does this mean for your code? Well, for one thing, you can use the subscript operator on mystring as though it were an array type:
printf("%s\n", &mystring[6]); // prints "World!"
Note that the subscript operator [] has higher precedence than the unary & operator, so the above is interpreted as &(mystring[6]) - we subscript into mystring and then take the address of the result.
You can pass mystring to any function that you would pass an array of char to:
void foo(char str[]) // identical to char *str
{
// do something with str
}
...
int main(void)
{
char str[] = "Hello, World!";
char *mystr = malloc(strlen(str) + 1); // note no cast
strcpy(mystr, str);
foo(str);
foo(mystr);
...
}
Again, as far as the function foo is concerned, its argument is type char *, not array of char. The expression str decays to a pointer value, and mystr is a pointer value to begin with.
A couple of things:
1) Allow for the null terminator in your "malloc()":
int strLen;
...
char *myString = (char*) malloc(strLen+1);
2) The "sizeof(char)" is kind of duplicate redundant. No harm - but no purpose, either. So I omitted it.
3) This is wrong:
for(int i=6;i<strLen;i++)
{
printf("%s", myString[i]);
}
4) This is better:
for(int i=6;i<strLen;i++)
{
printf("%c", myString[i]);
}
You can take the address of the character at a certain array index.
So, try this if you just want to print out 'world!':
#include <stdio.h>
int main(int a, char** b)
{
int strLen;
char *myString;
myString = "hello world!";
printf("%s", &myString[6]);
return 0;
}

C Programming - Pass-by-Reference

In the C program below, I don't understand why buf[0] = 'A' after I call foo. Isn't foo doing pass-by-value?
#include <stdio.h>
#include <stdlib.h>
void foo(char buf[])
{
buf[0] = 'A';
}
int main(int argc, char *argv[])
{
char buf[10];
buf[0] = 'B';
printf("before foo | buf[0] = %c\n", buf[0]);
foo(buf);
printf("after foo | buf[0] = %c\n", buf[0]);
system("PAUSE");
return 0;
}
output:
before foo | buf[0] = 'B'
after foo | buf[0] = 'A'
void foo(char buf[])
is the same as
void foo(char* buf)
When you call it, foo(buf), you pass a pointer by value, so a copy of the pointer is made.
The copy of the pointer points to the same object as the original pointer (or, in this case, to the initial element of the array).
C does not have pass by reference semantics in the sense that C++ has pass by reference semantics. Everything in C is passed by value. Pointers are used to get pass by reference semantics.
an array is just a fancy way to use a pointer. When you pass buf to the function, you're passing a pointer by value, but when you dereference the pointer, you're still referencing the string it points to.
Array as function parameter is equivalent to a pointer, so the declaration
void foo( char buf[] );
is the same as
void foo( char* buf );
The array argument is then decayed to the pointer to its first element.
Arrays are treated differently than other types; you cannot pass an array "by value" in C.
Online C99 standard (draft n1256), section 6.3.2.1, "Lvalues, arrays, and function designators", paragraph 3:
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. If the array object has register storage class, the
behavior is undefined.
In the call
foo(buf);
the array expression buf is not the operand of sizeof or &, nor is it a string literal being used to initialize an array, so it is implicitly converted ("decays") from type "10-element array of char" to "pointer to char", and the address of the first element is passed to foo. Therefore, anything you do to buf in foo() will be reflected in the buf array in main(). Because of how array subscripting is defined, you can use a subscript operator on a pointer type so it looks like you're working with an array type, but you're not.
In the context of a function parameter declaration, T a[] and T a[N] are synonymous with T *a, but this is only case where that is true.
*char buf[] actually means char ** so you are passing by pointer/reference.
That gives you that buf is a pointer, both in the main() and foo() function.
Because you are passing a pointer to buf (by value). So the content being pointed by buf is changed.
With pointers it's different; you are passing by value, but what you are passing is the value of the pointer, which is not the same as the value of the array.
So, the value of the pointer doesn't change, but you're modifying what it's pointing to.
arrays and pointers are (almost) the same thing.
int* foo = malloc(...)
foo[2] is the same as *(foo+2*sizeof(int))
anecdote: you wrote
int main(int argc, char *argv[])
it is also legal (will compile and work the same) to write
int main(int argc, char **argv)
and also
int main(int argc, char argv[][])
they are effectively the same. its slightly more complicated than that, because an array knows how many elements it has, and a pointer doesn't. but they are used the same.
in order to pass that by value, the function would need to know the size of the argument. In this case you are just passing a pointer.
You are passing by reference here. In this example, you can solve the problem by passing a single char at the index of the array desired.
If you want to preserve the contents of the original array, you could copy the string to temporary storage in the function.
edit: What would happen if you wrapped your char array in a structure and passed the struct? I believe that might work too, although I don't know what kind of overhead that might create at the compiler level.
please note one thing,
declaration
void foo(char buf[])
says, that will be using [ ] notation. Not which element of array you will use.
if you would like to point that, you want to get some specific value, then you should declare this function as
void foo(char buf[X]); //where X would be a constant.
Of course it is not possible, because it would be useless (function for operating at n-th element of array?). You don't have to write down information which element of array you want to get. Everything what you need is simple declaration:
voi foo(char value);
so...
void foo(char buf[])
is a declaration which says which notation you want to use ( [ ] - part ), and it also contains pointer to some data.
Moreover... what would you expect... you sent to function foo a name of array
foo(buf);
which is equivalent to &buf[0]. So... this is a pointer.
Arrays in C are not passed by value. They are not even legitimate function parameters. Instead, the compiler sees that you're trying to pass an array and demotes it to pointer. It does this silently because it's evil. It also likes to kick puppies.
Using arrays in function parameters is a nice way to signal to your API users that this thing should be a block of memory segmented into n-byte sized chunks, but don't expect compilers to care if you spell char *foo char foo[] or char foo[12] in function parameters. They won't.

Resources