String in function parameter - c

int main()
{
char *x = "HelloWorld";
char y[] = "HelloWorld";
x[0] = 'Z';
//y[0] = 'M';
return 0;
}
In the above program, HelloWorld will be in read-only section(i.e string table). x will be pointing to that read-only section, so trying to modify that values will be undefined behavior.
But y will be allocated in stack and HelloWorld will be copied to that memory. so modifying y will works fine. String literals: pointer vs. char array
Here is my Question:
In the following program, both char *arr and char arr[] causes segmentation fault if the content is modified.
void function(char arr[])
//void function(char *arr)
{
arr[0] = 'X';
}
int main()
{
function("MyString");
return 0;
}
How it differs in the function parameter context?
No memory will be allocated for function parameters??
Please share your knowledge.

Inside the function parameter list, char arr[] is absolutely equivalent to char *arr, so the pair of definitions and the pair of declarations are equivalent.
void function(char arr[]) { ... }
void function(char *arr) { ... }
void function(char arr[]);
void function(char *arr);
The issue is the calling context. You provided a string literal to the function; string literals may not be modified; your function attempted to modify the string literal it was given; your program invoked undefined behaviour and crashed. All completely kosher.
Treat string literals as if they were static const char literal[] = "string literal"; and do not attempt to modify them.

function("MyString");
is similar to
char *s = "MyString";
function(s);
"MyString" is in both cases a string literal and in both cases the string is unmodifiable.
function("MyString");
passes the address of a string literal to function as an argument.

char *arr;
above statement implies that arr is a character pointer and it can point to either one character or strings of character
& char arr[];
above statement implies that arr is strings of character and can store as many characters as possible or even one but will always count on '\0' character hence making it a string
( e.g. char arr[]= "a" is similar to char arr[]={'a','\0'} )
But when used as parameters in called function, the string passed is stored character by character in formal arguments making no difference.

Related

Why can I have a const char pointer point to a mutable char array?

Why is this fine:
char a[2];
a[0]='a';
const char* b;
b=a;
printf("%s\n",b);
a[0]='b';
printf("%s",b);
why can a pointer to a constant string point to a non constant string? Also how do string constants work when assigning them to variables? Why can you do this:
const char* b="hello";
b="test";
or
char* b="hello";
b="test";
but you can only do the first line if it is an array? constant or not?
Why can I have a const char * point to a mutable char array?
The const here with b puts a restriction on its use. It is not allowing some new usage, but potentially less. So no opening of Pandora's Box here.
char a[2];
const char* b = a;
b has read-access to the array. The array a[] may still change via a.
a[0]='y'; // OK
b[0]='z'; // leads to error like "error: assignment of read-only location "
Also how do string constants work when assigning them to variables? constant or not?
"hello" is a string literal of type char [6]. With const char* b1 = "hello" declaration and initialization, b1 is assigned a pointer of type char *. This could have been const char *, yet for historical reasons1 it is char *. Since it is char*, char* b2 = "hello"; is also OK.
const char* b1 = "hello";
char* b2 = "hello";
Also how do string constants work when assigning them to variables?
b="test";
As part of the assignment, the string literal, a char array, is converted to the address and type of its first element, a char *. That pointer is assigned to b.
1 const was not available in early C, so to not break existing code bases, string literals remained without a const.
You can always add const-ness to a type. This is a good thing, because it allows you to write functions that make some guarantees.
//Here we know *str is const, so the function will not change what's being pointed to.
int strlength(const char *str) {
int length = 0;
while (*str++)
++length;
return length;
}
int main(void) {
char a[2] = "a"; //a[0] and a[1] are mutable in main(), but not in strlength().
printf("%d", strlength(a));
}
Note that casting away const-ness leads to undefined behavior:
void capitalize(char *str) {
if (isalpha(*str))
*str = toupper(*str);
}
int main(void) {
const char *b = "hello";
capitalize((char*) b); //undefined behavior. Note: without the cast, this may not compile.
}
As for your second question, your first example is correct because the type of a string literal in C (i.e. any sequence of characters between double quotes) is of type const char*. This is valid:
const char *b = "hello"; //"hello" is of type const char*
b = "text"; //"text" is of type const char*
Because casting away const leads to undefined behavior, this code is invalid:
char *b = "hello"; //undefined behavior; "hello" is const char*
b = "text"; //undefined behavior; "text" is const char*
The case for arrays is a little more involved. When used in expressions, arrays act as pointers, but arrays are a fundamentally different type than pointers:
char a[10];
a = "hello"; //does not compile - "hello" is a const char*; a is a char[10]
However, when used in an initialization statement, the rules state that a const char* can be used to initialize a character array:
char a[10] = "hello"; //initialization - a is a char[10], "hello" is a const char*
//a will contain {'h','e','l','l','o',0,0,0,0,0}
Also, don't forget that you can assign a string literal to an array with strcpy:
char a[10];
strcpy(a, "hello");
assert(strcmp(a, "hello") == 0);
//a will contain {'h','e','l','l','o',0,x,x,x,x}
//here x's mean uninitialized

Conflicting point between char array and char pointer with returning the adress

Purpose : My main purpose was to create a string in some kind of function , it should return an adress , by returning adress using the string in main.
But I learned char array and char pointer actually using for the same purpose.
If we suppose that's true , We have these declaration :
char *arr and char arr[10] , *(arr+9)=arr[10] isn't it?
Application 1 does not work.
Application 2 does work fine.
Application 1:
#include <stdio.h>
char *foo(char arr[]);
int main(void)
{
char example[10];
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char arr[])
{
arr[10]="attempt";
return arr;
}
Application 2:
#include <stdio.h>
char *foo(char*);
int main(void)
{
char *example;
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char* arr)
{
arr="attempt";
return arr;
}
Your code will invoke undefined behavior in both segments. ( Even though you have observed that Code 2 works, it only seems to work. In reality a failure is lurking, and can show without warning. )
Make these corrections to address that problem, and see comments for explanations:
In code 1:
//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
//char example[10]; // this will invoke undefined behavior
char example[10] = {"something"}; // 'example' initialized with content,
// thus averting undefined behavior
//example=foo(example);
strcpy (example, foo(example)); // char array is not assignable using `=`
// use strcpy to transfer result of "foo"
printf("%s\n",example);
return 0;
}
char *foo(char arr[]) //note: char arr[] decays into char *arr
{
//char arr[10]="attempt"; // Error: redefinition of 'arr' with a
// different type: char[10] vs char *
arr = "attempt"; //because char [] decays into char *, 'arr' is usable as is.
return arr;
}
To answer your question in comments: Why using strcpy function [after variable example was initialized] is not a undefined behaviour.
First the definition of a C string is important to know. ( C string definition is found here. )
The variable example in its original form, i.e. initialized:
char example[10];
Can contain anything. For example:
|%|h|8|\#|d|o|-|~|*|U|?|?|?|?|
// ^end of memory for 'example`
// note that the character in example[9] == 'U', not NULL, therefore, not a C string.
This would cause the function strcpy() to fail. Initializing guarantees predictable results:
char example[10] = {"something"};//properly initialized
|s|o|m|e|t|h|i|n|g|0|?|?|?|?|
// ^end of memory for 'example`
//or
char example[10] = {0}; //also properly initialized
|0|0|0|0|0|0|0|0|0|0|?|?|?|?|
// ^end of memory for 'example`
(This would require an extra step to place proper content.):
strcpy(example, "something");
The only required adjustment to Code 2 is to initialize the pointer before using: (See the reason why pointer must be initialized here.)
char *foo(char*);
//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
{
//char *example; // passing this will envoke undefined behavior
char *example = NULL;// must initialize before using
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char* arr)
{
arr="attempt";
return arr;
}
Both do not "work" for different reasons.
The first is undefined behavior (UB) as code attempts to assign an element outside the bounds of example[10].
arr[0]='\0'; or arr[9]='\0'; would have been OK given the value passed to foo().
Converting the address of the string literal "attempt" to a char is not good code either. A well enabled compiler will warn of this basic coding lapse. #f3rmat example
char *foo(char arr[]) {
arr[10]="attempt"; <-- UB
return arr;
}
char example[10];
example=foo(example);
The 2nd is UB because code attempted to use an uninitialized value in passing a pointer. This "works" in that the UB of passing an uninitialized pointer is often benign. Since foo() does not use this "garbage" value and the rest of good is well defined, it "works".
char *foo(char* arr) {
arr="attempt";
return arr;
}
char *example;
example=foo(example); // UB - likely a garbage value is passed to `foo()`.
printf("%s\n",example); // `example` is now pointing to `"attempt"`.
I learned char array and char pointer actually using the same purpose.
Pointers and arrays are related, yet different. Avoid the "actually using the same purpose" idea.
An array is like a row of houses on a street. A pointer is the address of a house written on a piece of paper in your hand. Houses ≠ scrap of paper. You can refer to the house by its address or even a row of houses by the first house's address, yet a house and its address are different.
I tried to compile Code '1' and got the following error:
prog.c: In function ‘main’:
prog.c:8:12: error: assignment to expression with array type
example=foo(example);
prog.c: In function ‘foo’:
prog.c:14:12: warning: assignment makes integer from pointer without a cast [-
Wint-conversion]
arr[10]="attempt\n";
^
You get error: assignment to expression with array type example=foo(example); because in your left hand side, you're using an array type, which is not assignable. Assignment operator (=) needs to have a modifiable lvalue as its left operand.
You get a warning: assignment makes integer from pointer without a cast [Wint-conversion] arr[10]="attempt\n"; because the left hand side and the right hand side in this assignment have different types.
Pointer and array are not the same.
char *arr = "attempt"
Here you're creating a string constant "attempt" and assigning its address to arr which is valid
char arr[10];
arr = "attempt";
This is invalid.
you can add elements to the array by following methods.
char arr[10] = "attempt";
char arr[10] = {'a', 't', 't', 'e', 'm', 'p', 't'};
arr[0] = 'a';
arr[1] = 't'; // and so on.
when you are passing the array as an argument to another function
arr = foo(arr);
you are passing the address of the zeroth element in the array arr[0]
Hope that helps..
Char arrays can be initialized but cannot be assigned.
char example[10]="attempt";
is valid.
But
char example[10];
example="attempt"
is not valid.
More details here
Your second example works because you pass a uninitialized pointer to a function and return an address of the string literal attempt
which will work perfectly as mentioned in the answer by chux

Can you dereference a char pointer inside of a function?

I’m trying to deference a char pointer to a char array inside a function:
void getword(char *word)
{
*word = "bar";
}
int main()
{
char defword[4] = "foo";
getword(defword);
printf("%s\n", defword);
return 0;
}
I would expect to get "bar" as output but I seem to get the completely unrelated string '1oo'.
The type of a dereferenced char * is char — a primitive value type. In this case, *word is the same as word[0].
The type of "bar" is const char * — a pointer type.
You are assigning the value of a pointer to a character. I'm doubtful your compiler let that happen without squawking mightily.
In any event, look into strcpy. Leaving aside the horrible unsafety of it all, this will work better:
strcpy(word, "bar");

Confusing pointers and arrays in C

I'm trying to understand the mistake in the following code. The code is supposed to switch between two arrays.
What I saw is that it switches only the first 4 bytes. Is the following correct?
Passing &num1 or num1 is the same (both pass the address of the first element in the array).
The (char**) casting is wrong. That's because when you pass and array you pass the address it's laid in. So you actually pass here a void*.
How can I actually switch between these two arrays only by pointers? Is thatpossible?
I know it is possible if from the beginning I had defined char **num1 and char **num2. But I want it to stay with the array notation!
#include <stdio.h>
void fastSwap (char **i, char **d)
{
char *t = *d;
*d = *i;
*i = t;
}
int main ()
{
char num1[] = "hello";
char num2[] = "class";
fastSwap ((char**)&num1,(char**)&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
return 0;
}
Passing &num1 or num1 is the same (both pass the address of the first element in the array). Am I correct?
No. The first one is a pointer to the array itself (of type char (*)[6]), whereas in the second case, you have a pointer to the first element (of type char *; an array decays into a pointer to its first element when passed to a function).
The (char*) casting is wrong
Indeed, you are casting a char (*)[6] to a char **.
So you actualy pass here a void (Am i correct?).
No. Non sequitur. I don't see how the void type is relevant here. You have pointers, arrays, and eventually pointers to arrays.
Arrays are not pointers. Your code is trying to swap arrays, which does not make sense, since assignment to arrays is not permitted. What you probably want is
I. either get pointers to the first character of each string, and then swap the pointers themselves, like this:
void swap_pointers(const char **a, const char **b)
{
const char *tmp = *b;
*b = *a;
*a = tmp;
}
const char *p1 = "hello";
const char *p2 = "world";
swap_pointers(&p1, &p2);
II. Or use actual arrays, and you swap their contents:
void swap_contents(char *a, char *b, size_t n)
{
for (size_t i = 0; i < n; i++) {
char tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
char a1[] = "hello";
char a2[] = "world";
swap_contents(a1, a2, strlen(a1));
Also, you may want to read this.
1. Passing &num1 or num1 is the same (both pass the address of the first element in the array)
Not true, &num1 gives you a pointer to a pointer that points to the entire character string "hello" (char*[6]) while num1 is just a pointer to the character block "hello" (char[6]).
2. The (char*) casting is wrong. That's because When you pass and array you pass the address it's laid in. So you actualy pass here a void (Am i correct?).
It is still not a void, it's just a pointer to a character pointer. If it were void, then it would be perfectly valid to do something like void** myVoid = &num1. This will cause a syntax error unless you explicitly typecast your char** to a void** before you assign it.
The problem is your explicit type casting &num1 as a char** which is not correct, it is a char*[6]. But of course, you can't declare a variable as a char*[6] so it can't be used in this way. To fix it you need to declare your num1 and num2 as:
char* num1 = "hello";
char* num2 = "class";
instead and keep everything else the same. In fact, with this change there is no need to typecast your &num1 as a char** because it already is that.

Issue with string and pointers

Can somebody tell me why this program does not work?
int main()
{
char *num = 'h';
printf("%c", num);
return 0;
}
The error I get is:
1>c:\users\\documents\visual studio 2010\projects\sssdsdsds\sssdsdsds\sssdsdsds.cpp(4): error C2440: 'initializing' : cannot convert from 'char' to 'char *'
But if I write the code like that:
int main()
{
char num = 'h';
printf("%c", num);
return 0;
}
it's working.
char *num = 'h';
Here, the letter 'h' is a char, which you are trying to assign to a char*. The two types are not the same, so you get the problem that you see above.
This would work:
char *num = "h";
The difference is that here you're using double-quotes ("), which creates a char*.
This would also work:
char letter = 'h';
char* ptrToLetter = &letter;
You should read up on pointers in C to understand exactly what these different constructions do.
char * is a pointer to a char, not the same thing than a single char.
If you have char *, then you must initialize it with ", not with '.
And also, for the formatting representation in printf():
the %s is used for char *
the %c is only for char.
In thefirst case you declared num as a pointer to a char. In the second case, you declare it as a char. In each case, you assign a char to the variable. You can't assign a char to a pointer to a char, hence the error.
'h' = Char
"h" = Null terminated String
int main()
{
char *num = "h";
printf("%s", num); // <= here change c to s if you want to print out string
return 0;
}
this will work
As somebody just said, when you write
char *num = 'h'
The compiler gives you an error because you're trying to give to a pointer a value. Pointers, you know, are just variables that store only the memory address of another variable you defined before. However, you can access to a variable's memory address with the operator:
&
And a variable's pointer should be coerent in type with the element pointed.
For example, here is how should you define correctly a ptr:
int value = 5;
//defining a Ptr to value
int *ptr_value = &value;
//by now, ptr_value stores value's address
Anyway, you should study somewhere how this all works and how can ptrs be implemented, if you have other problems try a more specific question :)
When you are using char *h, you are declaring a pointer to a char variable. This pointer keeps the address of the variable it points to.
In simple words, as you simply declare a char variable as char num='h', then the variable num will hold the value h and so if you print it using printf("%c",num), you will get the output as h.
But, if you declare a variable as a pointer, as char *num, then it cannot actually hold any character value. I can hold only the address of some character variable.
For example look at the code below
void main()
{
char a='h';
char *b;
b=&a;
printf("%c",a);
printf("%c",b);
printf("%u",b);
}
here , we have one char variable a and one char pointer b. Now the variable a may be located somewhere in memory that we do not know. a holds the value h and &a means address of a in memory The statement b=&a will assign the memory address of a to b. Since b is declared as a pointer, It can hold the address.
The statenment printf("%c",b) will print out garbage values.
The statement printf("%u",b) will print the address of variable a in memory.
so there's difference between char num and char *num. You must first read about pointers. They are different from normal variables and must be used very carefully.

Resources