#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
Related
I wanted to return characters as a single string after making each character uppercase in C language (Not using printf or putchar). The aim is to return the value of the string after adding each character
#include <stdio.h>
#include <string.h>
char *my_upcase(char *param_1)
{
int j = 0;
char *result = "";
char *str;
while (j < strlen(param_1))
{
char toupper = param_1[j];
if(toupper >= 'a'){
// putchar(toupper - 32);
*str = toupper - 32;
strncat(result, &toupper -32, 1);
putchar(*str);
}else {
// putchar(toupper);
*str = toupper;
strncat(result, &toupper, 1);
putchar(*str);
}
j++;
}
return result;
}
The function implementation does not make sense.
Firstly if the function does not change the source string then its parameter should be declared with qualifier const
char * my_upcase( const char *param_1 );
This declaration
char *result = "";
declares a pointer to a string ;iteral. You may not change string literals. Any attempt to change a string literal results in undefined behavior.
This declaration
char *str;
declares an uninitialized pointer that has an indeterminate value. Dereferencing such a pointer results in undefined behavior.
You need to allocate dynamically a character array and copy into it characters of the source string converted to the upper case.
Using the function strncat is inefficient.
And do not use magic numbers like 32. Instead use the standard C function toupper declared in the header <ctype.h>
For example the function can be defined the following way
#include <string.h>
#include <ctype.h>
//...
char * my_upcase( const char *param_1 )
{
char *result = malloc( strlen( param_1 ) + 1 );
if ( result != NULL )
{
char *p = result;
while ( ( *p = toupper( ( unsigned char )*param_1 ) ) != '\0' )
{
++p;
++param_1;
}
}
return result;
}
Taking your comment to my answer
Thank you for your response. However, I am not allowed to change this
declaration char * my_upcase( const char *param_1 ); and the platform
will not allow toupper method
it seems the function must change the original passed string. In this case it can be defined the following way
char * my_upcase( char *param_1 )
{
for ( char *p = param_1; *p != '\0'; ++p )
{
if ( 'a' <= *p && *p <= 'z' )
{
*p = *p - 'a' + 'A';
}
}
return param_1;
}
i,m trying to write this code, it should counting the number of substring, which are not including in the string, for examples(below), in the main i was trying with pointer to work with String without using arrays but it didnt work at all!!
// count_target_string("abc of", "of") -> 1
// count_target_string("abcof", "of") -> 0
// count_target_string("abc of abc of", "of") -> 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int countTargetString(char* text , char* string){
char d[]=" ";
char * portion = strtok(text,d);
int result=0;
while (portion!=NULL){
if (strcmp(portion,string)==0){
result++;
}
portion = strtok(NULL,d);
}
return result;
}
int main(){
printf("%d\n",countTargetString("abc of abc of","of"));
char *test ="abc of abc of";
char *d = "of";
printf("%d\n",countTargetString(test,d));
return 0;
}
strtok modifies the string.
char *test ="abc of abc of"; defines the pointer to the string literal. Modification of the string literal invokes Undefined Behaviour (UB). It is why your code does "not work at all" Same if you pass string literal reference directly to the function (ie use a string literal as a parameter) countTargetString("abc of abc of","of"));.
Your pointer must reference a modifiable string:
int main()
{
char mystring[] = "abc of abc of";
char *test = mystring;
char *d = "of";
printf("%d\n",countTargetString(test,d));
}
In the both calls of the function countTargetString
printf("%d\n",countTargetString("abc of abc of","of"));
char *test ="abc of abc of";
char *d = "of";
printf("%d\n",countTargetString(test,d));
you are passing pointers to string literals.
Though in C opposite to C++ string literals have types of non-constant character arrays nevertheless you may not change a string literal. Any attempt to change a string literal results in undefined behavior.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
And the function strtok changes the source string inserting terminating zero characters '\0' to extract substrings.
It is always better even in C to declare pointers to string literals with the qualifier const.
Instead of the function strtok you can use function strstr.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
size_t countTargetString( const char *s1, const char *s2 )
{
size_t count = 0;
size_t n = strlen( s2 );
for ( const char *p = s1; ( p = strstr( p, s2 ) ) != NULL; p += n )
{
if ( ( p == s1 || isblank( ( unsigned char )p[-1] ) ) &&
( p[n] == '\0' || isblank( ( unsigned char )p[n] ) ) )
{
++count;
}
}
return count;
}
int main( void )
{
printf("%zu\n",countTargetString("abc of abc of","of"));
const char *test ="abc of abc of";
const char *d = "of";
printf("%zu\n",countTargetString(test,d));
}
The program output is
2
2
As you can see the function parameters are also declared with the qualifier const because the function does not change passed strings.
Pay attention to that in any case to count occurrences of substrings in a string it is a bad idea to change the original string.
While strtok will not work with a string literal, strspn and strcspn can be used.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int countTargetString(char* text , char* string){
char d[]=" ";
int result = 0;
size_t span = 0;
while ( *text) {
text += strspn ( text, d);
span = strcspn ( text, d);
if ( strncmp ( text, string, span)) {
++result;
}
text += span;
}
return result;
}
int main( void) {
printf("%d\n",countTargetString("abc of abc of","of"));
char *test ="abc of abc of";
char *d = "of";
printf("%d\n",countTargetString(test,d));
return 0;
}
int count_substr(const char* target, const char* searched) {
int found = 0;
unsigned long s_len = strlen(searched);
for (int i = 0; target[i]; i++) {
// use memcmp to NOT compare the null terminator of searched
if (memcmp(target + i, searched, s_len) == 0) {
found++;
i += s_len - 1;
}
}
return found;
}
This is a very basic implementation of substring counting. For the fastest solution possible, copy the boyer moore pattern matching algorithm from wikipedia or wherever you want and modify it to cound instead of terminationg on a match.
#include <stdio.h>
#include <stdlib.h>
char concaten(const char *str1,const char *str2);
int main()
{
printf("%s",concaten("Code","blocks"));
return 0;
}
char concaten(const char *str1,const char *str2) {
int i=0,j=0;
char *result;
while(*str1){
result[i++]=str1[i++];
}
while(*str2){
result[i+j++]=str2[j++];
}
return result;
}
I wrote this function to get two strings and add them to another third string; I don't understand where I am going wrong, as it doesn't print anything.
There are a number of problems with your concaten function.
First, it should be returning a char* pointer, not a char; thus, the declaration should look like this:
char* concaten(const char* str1, const char* str2);
Next, the function will need to allocate memory in which to store the concatenated strings; this can be done with the malloc() function, and the number of characters required will be the sum of the lengths of the two input strings plus one, for the required nul-terminator.
Third, the logic of your two loops is wrong. You are incrementing i and j twice per loop but not incrementing either of the source pointers.
Finally, you must add a nul-terminator at the end of your new string.
Here's a version with the above fixes applied:
char* concaten(const char* str1, const char* str2)
{
int i = 0, j = 0;
char* result = malloc(strlen(str1) + strlen(str2) + 1); // allow space for nul-terminator
while (*str1) {
result[i++] = *str1++; // Only increment i once and "str1" once
}
while (*str2) {
result[i + j++] = *str2++; // Only increment j once and "str2" once
}
result[i + j] = '\0'; // Add required nul-terminator
return result;
}
Also, as you have allocated memory (with the malloc call), you should release that when you're done with the data, using a call to free. Here's how your main might work:
int main(void)
{
char* answer = concaten("Code", "blocks");
printf("%s", answer);
free(answer);
return 0;
}
Note: You can also remove the j variable entirely, and just re-use the result[i++] expression in the second loop. I've left it in so that you can more easily relate my code to your own.
Your function has the return type char
char concaten(const char *str1,const char *str2);
but within the function you are returning the variable result
return result;
declared like a pointer of the type char *
char *result;
So the compiler will issue a message that you are trying to convert a pointer to an integer.
The function must be declared like
char * concaten(const char *str1,const char *str2);
The pointer result is not initialized and has an indeterminate value. You need to allocate memory where you will write concatenated strings.
The while loops in the function will be infinite if str1 and/or str2 are not empty strings due to conditions
while(*str1){
and
while(*str2){
These statements
result[i++]=str1[i++];
and
result[i+j++]=str2[j++];
invoke undefined behavior not only because the pointer result is not initialized but also because there is no sequence point between left and write operands where there is used the postfix increment operator ++.
Also the result string must be zero terminated.
If you are not allowed to use standard C string functions then your function can be implemented for example the following way
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = 0;
size_t n2 = 0;
while ( str1[n1] ) ++n1;
while ( str2[n2] ) ++n2;
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
char *p = result;
while ( *str1 ) *p++ = *str1++;
do
{
*p++ = *str2;
} while ( *str2++ );
}
return result;
}
Also you should not forget to free the allocated memory when the result string is not needed any more.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = 0;
size_t n2 = 0;
while ( str1[n1] ) ++n1;
while ( str2[n2] ) ++n2;
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
char *p = result;
while ( *str1 ) *p++ = *str1++;
do
{
*p++ = *str2;
} while ( *str2++ );
}
return result;
}
int main(void)
{
char *result = concatenate( "Code ", "blocks" );
if ( result != NULL ) puts( result );
free( result );
return 0;
}
The program output is
Code blocks
If you may use standard C string functions then the function concatenate can look as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = strlen( str1 );
size_t n2 = strlen( str2 );
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
memcpy( result, str1, n1 );
memcpy( result + n1, str2, n2 + 1 );
}
return result;
}
int main(void)
{
char *result = concatenate( "Code ", "blocks" );
if ( result != NULL ) puts( result );
free( result );
return 0;
}
The program output is the same as shown above that is
Code blocks
Aside from the fact that your function should not return char but char*, the expression result[i++] = str1[i++]; is not correct it lacks a sequence point. Furthermore result is an unitialized pointer, it cannot hold any data, you would need to make it point to some valid memory location.
You could do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concatenate(const char* str1, const char* str2 ){
char* result = malloc(strlen(str1) + strlen(str2) + 1);
if (result){
char* temp = result;
while (*str1 != '\0'){
*temp++ = *str1++;
}
while (*str2 != '\0'){
*temp++ = *str2++;
}
*temp = '\0'; // don't forget to null terminate the string
}
return result; // if memory allocation fails a null pointer is returned
}
The direct usage of the function in the printf statement will not allow you to free the memory and you would have a memory leak if the program didn't finish immediately, in these cases it's best to have the returned pointer assigned as to not lose track of the allocated memory:
int main(void){
char *result = concatenate("Code", "blocks");
if(result){
printf("%s", result);
free(result);
}
return EXIT_SUCCESS;
}
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[]
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[]) {
.
.
.
}