Passing a pointer as a shorter array - c

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.

Related

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

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.

Why is the output of this programm garbage? [duplicate]

This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 5 years ago.
I am wondering why the output is garbage? And how can I solve this problem?
#include<stdio.h>
char *Func(void);
int main()
{
char *string1;
string1 = Func();
puts(string1);
return 0;
}
char *Func(void)
{
char string2[10]="medo";
return string2;
}
Because string2 is only valid in the scope of Func.
An array decays into a pointer when assigning it to a pointer, passing it to a function or when used with return in a function returning a pointer.
An array decaying into a pointer means that it is converted to a pointer and the pointer points to the first element of the array.
With an array like this:
int arr[] = { 1, 2, 3 };
These are equivalent:
int *p1 = arr;
int *p2 = &arr[0];
The problem with Func is that it is returning a pointer that points to a memory location that is only valid while Func is running. Once Func returns, it is no longer valid and the program flow might replace these values immediately.
In your main function you pass this pointer to printf and because the location where string1 is pointing to isn't valid in main (it was only valid in Func), you get garbage. Actually that is undefined behaviour, and medo could have been printed as well.
How to fix it: declare an array in main, pass it to Func, let Func use the
passed array and return:
#include<stdio.h>
#include<string.h>
Func(char* string2);
int main()
{
char string1[20];
Func(string1);
puts(string1);
return 0;
}
void Func(char *string2)
{
strcpy(string2, "medo");
}
Because the lifetime of the string has already ended by the time you print it.
Local variables, such as string2 in Func, are often stored in the stack, which is a very dynamic structure that changes every time a function is called or returned. (The actual behavior of the program stack is a bit too complex to elaborate here, but keep in mind that stuff in the stack doesn't survive the function that puts it there.)
By the time the function returns, string2 is no longer necessary, and thus it might be overwritten with garbage data. Nevertheless, Func returns a pointer to string2 (remember that the name of an array is a pointer to its contents) — thus returning a pointer to the stack-allocated string that is being overwritten with garbage data. Printing the data referenced by this pointer (in main, via string1) just prints that garbage.
There are two ways of solving this issue. One is to let the caller handle memory allocation, and pass the allocated area to the callee, like so:
#include <stdio.h>
#include <string.h>
void Func(char *);
int main (void) {
char string[10];
Func(string);
puts(string);
return 0;
}
void Func (char * string) {
strcpy(string, "test");
}
...and another way is to let the callee handle the allocation, but remembering that the caller must free it, like so:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * Func(void);
int main (void) {
char * string = Func();
puts(string);
free(string);
return 0;
}
char * Func (void) {
char * string = malloc(10);
strcpy(string, "test");
return string;
}
Either way would solve your issue, and which one you choose is a matter of design.

How to correctly pass a String array as function argument?

I know this has been asked numerous times before. However, I'm unable to get rid of a warning.
void function (char** cppStringArray);
int main(void) {
char cStringArray[5][512]={"","","","",""}; //Array of 5 Strings (char arrays) of 512 characters
function (cStringArray); //warning: incompatible pointer type
return 0;
}
How do I get rid of the warning? It works if I declare the Stringarray as char* cStringArray[5].
If your string array will remain with those sizes then the best way is to use
void function (char (* cppStringArray)[512], size_t num_strings);
pass as
function(cStringArray, sizeof(*cStringArray)/sizeof(cStringArray));
Problem is that char** is not equivalent to char (*)[512]. The former is a pointer to pointer to char. The latter is a pointer to a block of 512 characters.
Define the function like below.
void function (char cppStringArray[5][512]);

passing only first element of the array of chars to a function c++

Basically I have an array of words
void print(char *str) {
cout << str <<endl;
}
int main() {
int i =0;
char* name[] = {"Fred", "John", "Jimmy"};
print(*name[0]);
}
I would like to pass only first word to a function, but when I am doing in a way as I am doing right now it passes all the names.
You have an extra dereference there, the code should be like this:
print(name[0]);
Ideally, your print function should take const char*, because it does not modify the strings passed in.
char* name[] is an array of pointers to char, typically strings.
void print(char *str) requires a single pointer to a char as an argument.
By calling print(*name[0]), you are actually taking the first pointer from your name[] array, and dereferencing it to turn it into a single char. Since your function requires a pointer to char, you simply need to call it with print(name[0]) and you'll get the first item in your array.

defining a string value for structure variable

I was just going through certain interview questions. Got this structure related issue, I m not understanding what is happening wit the output, Please if some could explain the reason.
When is use a character pointer in the structure like
#include <stdio.h>
struct name {
char *array;
}variable;
int main( int argc, char * argv[] ){
variable.array="hello";
printf( "%s\n", variable.array );
}
The output is hello printed, but when change the structure variable to
struct name {
char array[10];
}variable;
The compiler throws an error "incompatible types in assignment" at
variable.array="hello";
I am really confused as to where i am missing the point. Why does it show the error like assignment problem?? Please correct me
Thank you
You can only initialize array like that at the time of declaration only,
else you need to use
strcpy(variable.array,"hello");
you can't even do like that with a simple char array
char a[10];
a="hello";
the complier will tell :
incompatible types when assigning to type ‘char[10]’ from type ‘char *’
because "hello" is a string literal that is being held by a pointer which can't be assigned like this to an array.
In C the term "hello" means "a pointer to a string that has the chars 'hello\0' in it".
So when you assign array="hello" in the first case you are assigning the pointer to the string into a pointer variable. Which is right.
In the second case you try to assign a pointer to an array which is wrong!
you can't assign value to an array.
It raises an error because an array of char and a pointer to char are different things.
An array is not a pointer. A pointer is not an array. Sometimes a pointer might point to an array. But even when a pointer points to an array, it's not an array.
Your compiler gives an address to variable.array at compile time. It also gives an address to the string literal "hello". They're not the same address. The string literal and the array (or "the buffer") are in different places; logically, the string has to be copied into the buffer.
#include <stdio.h>
#include <string.h>
struct name {
char array[10];
}variable;
int main( void ){
strcpy(variable.array, "hello");
printf( "%s\n", variable.array );
return 0;
}
You might find the C FAQ useful.
The first thing is array is a constant pointer to the first element in the
array,we can not change its address location once we declared..like
int a[3]; is equivalent to int *const a;
so we cant change the array address location
int a[3]={1,2,3};
a++;//its an error
int b[3];
b=a;//its also an error
but int *c;
c=a;//Not an error because c is a pointer to integer not constant pointer to integer
similar to
char str[10]="hello";
if i change like this
str="world";//its also an error
Pointers and arrays are always not equal, in some cases only like dereferencing
char a[10]="hello";
for(i=0;a[i]!='\0';i++)
printf("%c",a[i]);
for(i=0;a[i]!='\0';i++)
printf("%c",*(a+i));

Resources