How do I pass an array as an argument to a function? - c

I have read the post here on the same subject, but it doesn't seem to have the solution to my problem.
If I need to write a function str_reverse() which reverses any string passed to it, how can I go about it? Just as the person who asked the question I linked above, the following code
#include <stdio.h>
#include <string.h> //for strlen
#define maxL 300 //Max String Length
void str_reverse(char);
int main(){
//Variables
char x[maxL];
//User Prompt
printf("Enter a string no longer than %d characters: ", maxL);
gets(x);
str_reverse(x);
//Return Statement
return 0;
}
void str_reverse(char x){
int i, l;
l = strlen(x);
printf("In reverse: ");
for(i=l-1; i>=0; i--)
printf("%c",x[i]);
}
gives me an error. How can I create a program which allows me to reverse the string?

You are passing fine but the function isn't receiving properly. Change it to:
void str_reverse(char *x){
..
}
and the prototype to:
void str_reverse(char*);
Also, gets() is dangerous and should never be used. Use fgets() instead:
if( fgets(x, sizeof x, stdin) == NULL) { /* failure */ }
x[strcspn(x,"\n")] = 0; // to remove the trailing newline, if any.

Your can pass array as type arr[] or as type * pointer. you will have to pass length as an argument to your string reverse function. New declaration of string reverse will look like this:
void str_reverse(char *x,int length)
or
void str_reverse(char x[],int length)
for more information you can follow Length of array in function argument

A function parameter declared as an array is adjusted to pointer to array element.
Thus these function declarations are equivalent and declare the same one function
#define maxL 300
void str_reverse(char[maxL]);
or
void str_reverse(char[10]);
or
void str_reverse(char[1000]);
or
void str_reverse(char[]);
or
void str_reverse( char *);
And on the other hand when an array is passed as an argument to a function it is implicitly converted to pointer to its first element.
So this function call
char x[maxL];
//...
str_reverse(x);
can be imagine like
char x[maxL];
//...
char *tmp = x;
str_reverse(tmp);
Take into account that function gets is unsafe and is not supported by the C Standard any more.
Use instead standard function fgets
Also it is better if the function returned pointer to its first character.
Your function does not try to reverse a string. It tries to output a string in the reverse order.
So the function that indeed reverses a string can be written like
char * str_reverse( char *s )
{
size_t n = strlen( s );
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n- i-1];
s[n-i-1] = c;
}
return s;
}
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
#define maxL 300 //Max String Length
char * str_reverse( char *s )
{
size_t n = strlen( s );
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n- i-1];
s[n-i-1] = c;
}
return s;
}
int main( void )
{
//Variables
char s[maxL];
//User Prompt
printf("Enter a string no longer than %zu characters: ", maxL);
fgets( s, maxL, stdin );
s[strcspn( s, "\n" )] = '\0';
puts( str_reverse( s ) );
return 0;
}
Its output might look like
Enter a string no longer than 300 characters: Hello, World!
!dlroW ,olleH

You can achieve this by many different ways:
Option-1
Formal parameters as a pointer −
void myFunction(char *param) {
.
.
.
}
Option-2
Formal parameters as a sized array −
void myFunction(char param[10]) {
.
.
.
}
Option-3
Formal parameters as an unsized array −
void myFunction(char param[]) {
.
.
.
}

Related

strstr not working with needles shorter than 3 char

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* findSequence(char s[], char ch, int n){
int i;
char*ptr;
char needle[n];
char*npdr=&needle;
for(i=0;i<n;i++){needle[i]=ch;}
ptr = strstr(s,ndpr);
printf("%s",ptr);
return ptr;
}
int main()
{
char stringa[]={"ciccciopasticcio"};
char carattere='c';
char*ptr;
int n=3;
ptr=findSequence(stringa, carattere,n);
return 0;
}
This quick code, should search for a matching between a string and a needle of non set lenght, it works just fine with any n>=3 the problem is with 1 and 2 as n values.
watching the debug i noticed that the pointer npdr adds a second and third value to the sequence on his own example: n=2 needle="cc" npdr=address of needle[0] "cc#"
Do you have any ideas of why this is happening?
The standard function strstr expects two pointers to strings. But you are calling the function passing an array as the second argument that does not contain a string - a sequence of characters terminated by the zero character '\0'
char needle[n];
char*npdr=&needle;
for(i=0;i<n;i++){needle[i]=ch;}
ptr = strstr(s,ndpr);
So the code invokes undefined behavior.
Also this initialization
char*npdr=&needle;
is incorrect. The initialized pointer has the type char * while the initializing expression has the type char ( * )[n]. At least you need to write
char*npdr=needle;
You could declare the array like
char needle[n + 1];
and
needle[n] = '\0';
Pay attention to that the function should not output any message. It is the caller of the function will decide whether to output a message. Moreover this call of printf
printf("%s",ptr);
will invoke undefined behavior if the pointer ptr is equal to NULL.
The function itself should be declared the following way
char* findSequence(const char s[], char ch, size_t n);
That is the first parameter should be declared with the qualifier const because passed strings are not changed within the function. And the second parameter should have unsigned integer type size_t instead of the signed integer type int.
Also using a variable length array within the function makes the function unsafe.
The function can be defined using standard C string function strchr instead of the function strstr.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
char * findSequence( const char s[], char ch, size_t n )
{
const char *p = NULL;
if (n != 0 && ch != '\0')
{
size_t count = 0;
do
{
count = 0;
p = strchr( s, ch );
if (p)
{
s = p;
do
{
++count;
} while (*++s == ch);
}
} while (p != NULL && count != n);
}
return ( char * )p;
}
int main( void )
{
char stringa[] = { "ciccciopasticcio" };
char carattere = 'c';
size_t n = 3;
char *ptr = findSequence( stringa, carattere, n );
if (ptr != NULL)
{
puts( ptr );
}
}
The program output is
ccciopasticcio

problem in returning array address from function in C

There comes an error "conflicting types" so what can I do, and prefer a good alternative for this. The main problem is in returning an array from function
#include<stdio.h>
int* freqofchar(char);
int main()
{
char str[100];
printf("Enter a sentence below :\n");
gets(str);
int* p = freqofchar(str);
for(int i=0;i<128;i++){
if(*p>0){
printf("%c occurred %d times\n",(char) i , *p++);
}
}
return 0;
}
int* freqofchar(char str[]){
int freq[128] = {0};
for(int i = 0;str[i] != '\0';i++){
freq[ str[i] ]++;
}
return freq;
}
You have 2 problems:
1) conflicting types:
int* freqofchar(char)
in declaration, but
int* freqofchar(char str[])
in definition.
2) You are returning freq allocated on stack from freqofchar
The error you see is due to mismatch in the function prototype and its actual definition.
However, you have other problems, too:
gets function has been removed from the C standard (since) for a good reason and should never be used in any case. You can use fgets instead to read input. But you need to remove the newline if fgets reads it in.
You are returning a pointer to a local variable, whose lifetime isn't valid once the function freqofchar returns, which is undefined behaviour. You can instead pass another argument. Generally you may want to consider dynamic allocation (e.g. via malloc) but in this case - you only need a small array - an array local to the main function, which has automatic storage duration and thus its lifetime is valid for the duration of main() and it can be safely passed to freqofchar function without it being invalid or de-allocated as the object's (freq being the object in reference here) lifetime is still valid in when it's being used in freqofchar() - is better-suited here.
Here's how a fixed solution would looks like:
#include<stdio.h>
#include<string.h>
void freqofchar(char*, int*);
int main()
{
char str[100] = {0};
int freq[256] = {0};
printf("Enter a sentence below :\n");
fgets(str, sizeof str, stdin);
/* Remove the newline if present. */
char *p = strchr(str, '\n');
if (p) *p = '\0';
freqofchar(str, freq);
for(size_t i = 0;i < sizeof freq; i++) {
if(freq[i]) {
printf("%c occurred %d times\n", i, freq[i]);
}
}
return 0;
}
void freqofchar(char str[], int freq[])
{
for(int i = 0;str[i] != '\0';i++) {
freq[ str[i] ]++;
}
}
The function parameter is declared in the function declaration as having the type char
int* freqofchar(char);
^^^^^
But in the function declaration that at the same is its definition
int* freqofchar(char str[]){
^^^^^^^^^
the parameter is declared as having the type char [] (that is adjusted by the compiler to the type char *).
This typo is the reason of the compiler message.
But in any case the function shall be declared at least like
unsigned int * freqofchar( const char [] );
That is there is no sense to define frequencies as having signed integer type and the parameter shall have the qualifier const because the passed string is not being changed in the function.
The program has undefined behavior because the function returns pointer to a local array with the automatic storage duration that will not be alive after exiting the function.
int* freqofchar(char str[]){
int freq[128] = {0};
//...
return freq;
}
You should either allocate the array dynamically or declare it with the storage specifier static. In the last case you need to reset elements of the array to zeroes each time when the function is called.
The function gets is an unsafe function and is not supported by the C standard any more. Instead use the standard C function fgets.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned int* freqofchar( const char *);
int main( void )
{
enum { N = 100 };
char str[N];
str[0] = '\0';
printf( "Enter a sentence below : " );
fgets( str, N, stdin );
// remove the appended new line character '\n'
str[ strcspn( str, "\n" ) ] = '\0';
unsigned int *p = freqofchar( str );
for ( size_t i = 0; i < 128; i++ )
{
if ( p[i] )
{
printf( "'%c' occurred %u times\n", ( char )i , p[i] );
}
}
free( p );
return 0;
}
unsigned int * freqofchar( const char str[] )
{
enum { N = 128 };
unsigned int *freq = calloc( N, sizeof( unsigned int ) );
while ( *str ) ++freq[ ( size_t )*str++ ];
return freq;
}
Its output might look like
Enter a sentence below : Hello World!
' ' occurred 1 times
'!' occurred 1 times
'H' occurred 1 times
'W' occurred 1 times
'd' occurred 1 times
'e' occurred 1 times
'l' occurred 3 times
'o' occurred 2 times
'r' occurred 1 times
If to define the function with the static storage specifier then its definition can look the following way.
#include <stdio.h>
#include <string.h>
unsigned int* freqofchar( const char *);
int main( void )
{
enum { N = 100 };
char str[N];
str[0] = '\0';
printf( "Enter a sentence below : " );
fgets( str, N, stdin );
// remove the appended new line character '\n'
str[ strcspn( str, "\n" ) ] = '\0';
unsigned int *p = freqofchar( str );
for ( size_t i = 0; i < 128; i++ )
{
if ( p[i] )
{
printf( "'%c' occurred %u times\n", ( char )i , p[i] );
}
}
return 0;
}
unsigned int * freqofchar( const char str[] )
{
enum { N = 128 };
static unsigned int freq[N];
memset( freq, 0, N * sizeof( unsigned int ) );
while ( *str ) ++freq[ ( size_t )*str++ ];
return freq;
}
You make one of the most common mistakes in the C programming. You return the pointer to the object which does not exist after the function return.
possible solutions
a. use dynamicaly allocated memory
int* freqofchar(char *str)
{
int *freq = malloc(128 * sizeof(*freq)); // or if you want to zero it calloc
/* ... */
return freq;
}
but you need to free the allocated memory when not needed.
b. use static array or global array
int* freqofchar(char *str)
{
static freq[128];
/* ... */
return freq;
}
or
static freq[128];
int* freqofchar(char *str)
{
/* ... */
return freq;
}
Downsides of this solution: the function is not reentrant, the freq array cannot be passed to the async task and functions as it can be changed if function is called again.
The initialisation happens only one time before first call to the function.
c. Wrap it in the union or struct and return the whole object
struct freqstruct {
int freq[128];
};
struct freqstruct freqofchar(char *str)
{
struct freqstruct freq = {0};
/* ... */
return freq;
}
Downside - the whole array wrapped into the struct is copied. It is not very memory and performance wise.
Your definition does not match the declaration of the function. It shows that you did not put enough effort.
int* freqofchar(char *str)
int* freqofchar(char *str)
{
/* ... */
}
or - but I personally do not like this notation as it makes beginners think that the array is passed not the pointer.
int* freqofchar(char str[])
int* freqofchar(char str[])
{
/* ... */
}
This functions is not const corrent - the parameter str should be const char *str or const char str[]

What's wrong with this recursion program

I'm trying to reverse a string using recursion but it's not working.
What's the mistake?..
It's showing some output "tset a ♠♣♦♥☻☺" for test case "this is a test"
#include "stdio.h"
#include "string.h"
void rec(char [],int,int);
void main()
{
char ch[50];int j,i=0;
printf("Enter the string: ");
gets(ch);
j=strlen(ch)-1;
rec(ch,i,j);
puts(ch);
}
void rec(char ch[],int i,int j)
{
char t;
if(i>=j) return;
t=ch[i];
ch[i]=ch[j];
ch[j]=i;
rec(ch,++i,--j);
}
ch[j]=i;
You are assigning an integer to character which is not what you want.
You are storing the value in t so
ch[j] = t;
is what you need.
In this statement
ch[j]=i;
you are using i instead of t
The function could be written simpler with only two parameters. For example
void rec( char s[], size_t n )
{
if ( !( n < 2 ) )
{
char c = s[0];
s[0] = s[n-1];
s[n-1] = c;
rec( s + 1, n - 2 );
}
}
and called like
rec( ch, strlen( ch ) );
Now try to write the function with only one parameter: char s[]:)
You need to change
ch[j]=i;
to
ch[j]= t;
Note that no need to null terminate the string explicitly. strlen gives th length the string excluding the \0 character. You are passing strlen(ch)-1 to your function it means it will start reversing the characters from the character just before \0. So, after the reversal the string will be null terminated.

void function(no printing)- reverse a string using recursion

I want to write a recursive function in C languge that revers a word. I know how to do it with printing it, but actually reversing the original word I don't know how.
so, I want to write a function that revers a word, using pointers, using string.h, but has to be void, no printing, and changing the original word. the function prototype:
void reverse(char* string);
what I was able to write were the stop terms of the recursion(and i'm not sure if they are correct);
if(!string) return; // if the string is empty
if(*(string+1)=='\0' return (*string); // if there is only on char in the string
if(*(string+2))=='\0' // if there are only 2 letters In the strings-swap
temp=(*string);
(*string)= * (string+1);
(*string+1)= temp; // I don't know what to do after..
that would be great is go guys can explain to me what to do.
thank you.
An implementation with tail recursion:
#include <stdio.h>
#include <string.h>
/* function prototypes */
void reverse(char *string);
void reverseWorker(char *string, int start, int end);
int main(int argc, const char *argv[]) {
char string[] = "Hello, world.";
printf("string (original) = %s\n", string);
/*
reverse(string);
Or, to reverse each word in the string...
*/
char *ptr = strtok(string, " ");
while(ptr != NULL) {
reverse(ptr);
ptr = strtok(NULL, " ");
if(ptr != NULL)
*(ptr-1)=' ';
}
/* the rest is the same */
printf("string (reversed) = %s\n", string);
return 0;
}
void reverse(char *string) {
reverseWorker(string, 0, strlen(string)-1);
}
void reverseWorker(char *string, int start, int end) {
/* terminal condition */
if(start>=end)
return;
/* swap */
char temp = string[start];
string[start]=string[end];
string[end]=temp;
/* recursive step */
reverseWorker(string,start+1,end-1);
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void reversefill(char*const from,char*const to){
if(from>=to){
//Nothing to do. Odd lengths get to from==to.
//Even lengths 'swap over'.
//Pointer comparison guaranteed legit - in the same array.
return;
}
//Textbook swap.
//Could use the classic xor swap trick.
//However that will just confuse in this example.
const char temp=*from;
*from=*to;
*to=temp;
//Carry on moving our 'work' points closer together from both ends.
reversefill(from+1,to-1);
}
void reverse(char* str){
const size_t sz=strlen(str);
if(sz==0){
return;//Can't use str-1 - UB.
//Could head for the door if sz==1 but this is a training example on recursion.
//So we'll just show it works if from==to.
}
reversefill(str,str+sz-1);
}
int main() {
char*const str="Hello World!";
char*const rev=malloc(strlen(str)*sizeof(*str));//sizeof not required but good habit
strcpy(rev,str);
reverse(rev);
printf("%s\n",rev);
free(rev);//Don't listen to smart-arses who say that's unnecessary.
//Unless you really need to use the trick...
//However examples should be the cleanest possible code.
return EXIT_SUCCESS;
}
I think the requirement was in-place reversal.
The only way to do that (I think the OP realises) is to work from the ends and swap 'symmetric' positions. That is swap the first with last, second with second last, etc.
That's fine but we need to realise when we've 'met' in the middle.
That's obvious of odd length cases - the two working points meet.
For even cases we need to spot the workings 'crossing over'.
That's exactly how reversefill(,) works.
I think this code is an excellent specimen of the strengths and weaknesses of C strings.
The main function is fantastically efficient.
But actually has to scan the string twice because C doesn't intrinsically provide a O(1) way of obtaining the length of a string!
You could write the function like
void reverse( char s[] )
{
reverse_impl( s, strlen( s ) );
}
void reverse_impl( char s[], size_t n )
{
if ( !( n < 2 ) )
{
char c = s[0];
s[0] = s[n-1];
s[n-1] = c;
reverse_impl( s + 1, n - 2 );
}
}
But it is a wrong solution because it is not function void reverse( char s[] ); that is a recursive function. It is function void reverse_impl( char s[], size_t n ); that is recursive. But according to your assignment it is function void reverse( char s[] ); that has to be recursive.
So the correct solution is the following.
#include <stdio.h>
void reverse( char s[] )
{
if ( *s )
{
char *p = s;
char c;
do
{
c = *p;
*p = *( p + 1 );
*( p + 1 ) = c;
} while ( *p++ );
reverse( s );
c = *p;
*p = *( p - 1 );
*( p - 1 ) = c;
}
}
int main( void )
{
char s[] = "abcde";
puts( s );
reverse( s );
puts( s );
return 0;
}
The output is
abcde
edcba
This recursive function uses neither standard function :)

Returning string from function having multiple NULL '\0' in C

I am compressing string. And the compressed string sometimes having NULL character inside before the end NULL. I want to return the string till the end null.But the compressor function is returning the sting till the occurring of the first NULL. Please help me.
char* compressor(char* str)
{
char *compressed_string;
//After some calculation
compressed_string="bk`NULL`dk";// at the last here is automatic an NULL we all know
return compressed_string;
}
void main()
{
char* str;
str=compressor("Muhammad Ashikuzzaman");
printf("Compressed Value = %s",str);
}
The output is : Compressed Value = bk;
And all other characters from compressor function is not here. Is there any way to show all the string.
The function returns "entire string". It is printf that outputs it until the null character will be encountered.
You could define the function the following way
char * compressor( const char* source, size_t *result_len );
To understand the problem consider the following code
#include <stdio.h>
char * compressor( const char* source, size_t *result_len )
{
char *compressed_string = "bk\0dk";
*result_len = sizeof( "bk\0dk" );
return compressed_string;
}
int main( void )
{
char* str;
size_t n;
str = compressor( "Muhammad Ashikuzzaman", &n );
int i;
printf( "Compressed Value = " );
for ( char *p = str; n; n -= i + 1, p += i + 1 )
{
i = printf( "%s", p );
}
return 0;
}
The output is
Compressed Value = bkdk
#include <stdio.h>
#include <stdlib.h>
char* func(char *str, int *length)
{
int i;
*length=9;//Put string length you calculated
str=(char*)malloc(*length*sizeof(char));
for(i=0;i<5;i++)
str[i]=i+65;
str[5]=0;
str[6]=65;
str[7]=67;
str[8]=0;
return str;
}
int main()
{
char *str;
int i,length=0;
str=func("Muhammad Ashikuzzaman",&length);
for(i=0;i<length;i++)
printf("%c",str[i]);
scanf("%d",&i);
return 0;
}
Solution using std::string:
#include <string>
#include <iostream>
#include <iterator>
std::string compressor(char* str)
{
char *compressed_string;
int len; // this is the size of the compressed data
//...
// compress the data and assume that len has the number of characters
//...
std::string theString(compressed_string, len);
// clean up any memory here.
//...
return theString;
}
using namespace std;
int main()
{
std::string str = compressor("Muhammad Ashikuzzaman");
std::copy(str.begin(), str.end(), std::ostream_iterator<char>(cout,""));
}
Note the usage of std::string, as well as how the information is outputted using the copy algorithm function. The reason why copy is used instead of printf is to ensure that all of the characters, including the (invisible) embedded NULL's are printed.
Also, the size of the compressed data is easily retrieved by calling str::size().

Resources