I have created a function that should find the numerical position of the first character of a substring in a larger string. I am having some problems with the output and I am not too sure why. These problems include -1 being returned every single time instead of the integer position of the substring. I have debugged and cannot trace where the function goes wrong.
This is how the function should perform: If my string is "The dog was fast" and I am searching for the substring "dog", the function should return 4. Thanks to chqrlie for help with the loop.
Here is the function:
int findSubString(char original[], char toFind[]) {
size_t i, j;
int originalLength = 0;
int toFindLength = 0;
originalLength = strlen(original) + 1;
toFindLength = strlen(toFind) + 1;
for (i = 0; i < toFindLength + 1; i++) {
for (j = 0; j < originalLength + 1; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
The function parameters cannot be modified, this is a requirement. Any help appreciated!
These statements inside the loops
if (toFind[j] == '\0') {
return i;
}
results in undefined behavior because the string toFind can be shorter than the string original.
The same is valid for this loop
if (original[i + j] != toFind[j]) {
break;
}
because i + j can be greater than the length of the string original.
And there is no need to scan all characters of the string original if you are going to find a substring inside it.
Also you should check whether the length of the string original is not less than the length of the string toFind.
If you want to find only the first character of the string toFind in the string original it is enough to use standard C function strchr. If you want to find the whole string toFind in the string original then you could use another C standard function strstr.
If you want to write the function yourself to find a string in other string then it can look for example the following way
I declared the function like
long long int findSubString( const char original[], const char toFind[] );
however you can write its declaration as you like for example like
int findSubString( char original[], char toFind[] );
But in this case you should declare function local variable success like
int success = -1;
and output the result using format specifier "%d" instead of "%lld".
Here you are.
#include <stdio.h>
#include <string.h>
#include <stddef.h>
long long int findSubString( const char original[], const char toFind[] )
{
size_t n = strlen( original );
size_t m = strlen( toFind );
long long int success = -1;
if ( !( n < m ) )
{
n = n - m + 1;
for ( size_t i = 0; success == -1 && i < n; i++ )
{
size_t j = 0;
while ( j < m && original[i+j] == toFind[j] ) j++;
if ( j == m ) success = i;
}
}
return success;
}
int main(void)
{
printf( "%lld\n", findSubString( "The dog was fast", "dog" ) );
return 0;
}
Its output is
4
Your loops are reversed. The outer loop should walk positions from zero to originalLength, inclusive; the nested loop should walk positions from zero to toFindLength, inclusive.
Both originalLength and toFindLength should be set to values returned by strlen, not strlen plus one, because null terminator position is not a good start.
Finally, you are returning -1 from inside the outer loop. This is too early - you should be returning -1 only after you are done with the outer loop as well.
Your loop counter tests are incorrect: wrong upper limit and the limits are off by one. Note that the tests are actually not necessary as you exit both loops when hitting the '\0' terminators.
Here is a simpler version:
int findSubString(const char *original, const char *toFind) {
for (size_t i = 0;; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
There is a small advantage at computing the string lengths to reduce the number of comparisons in pathological cases such as findSubString("aaaaaaaaaaa", "aaaaaaaaaaaa");
int findSubString(const char *original, const char *toFind) {
size_t originalLength = strlen(original);
size_t toFindLength = strlen(toFind);
if (toFindLength <= originalLength) {
for (size_t i = 0; i <= originalLength - toFindLength; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
}
}
return -1;
}
Related
I'm wondering why my duplicate check is giving me wrong output. The idea is to built a nested loop, that compares every following letter in an array, with the initial loop's one. However, if I print the results, the function gives back true when A = K e.g. and I don't understand that behaviour. Anyone able to explain what's happening here?
for (int n = 0; n < strlen(argv[1]) ; n++)
{
for (int i = 0; i < strlen(argv[1]) ; i++)
{
if (argv[1][n] == argv[1][i + 1])
{
printf("argv[1][n] = %c\n", argv[1][n]);
printf("argv[1][i] = %c\n", argv[1][i]);
printf("Error.\n");
return 0;
}
}
}
A more efficient way to check for duplicate chars in a string. Only requires one for-loop instead of a nested pair of loops. Assumes an 8-bit char - hence 256 as array size.
size_t table[256] = {0};
size_t positions[256] = {0};
const char* sz = argv[1];
const size_t len = strlen(argv[1]);
for (size_t i = 0; i < len; i++)
{
unsigned char index = (unsigned char)(sz[i]);
table[index]++;
if (table[index] > 1)
{
printf("duplicate char %c found at index %d. Originally seen at index %d\n", sz[i], i, (int)(positions[index]));
return 0;
}
else
{
positions[index] = i;
}
}
These for loops
for (int n = 0; n < strlen(argv[1]) ; n++)
{
for (int i = 0; i < strlen(argv[1]) ; i++)
{
if (argv[1][n] == argv[1][i + 1])
{
//...
}
}
}
do not make a sense because argv[1][n] can be the same letter at the same position as argv[1][i+1] because the inner loop starts from 0.
Also you are outputting a letter at position i
printf("argv[1][i] = %c\n", argv[1][i]);
but in the preceding if statement you are checking a letter at the position i + 1.
The loops can look the following way
for ( size_t i = 0, n = strlen( argv[1] ); i < n ; i++ )
{
for ( size_t j = i + 1; j < n; j++ )
{
if ( argv[1][i] == argv[1][j] )
{
printf( "argv[1][i] = %c\n", argv[1][i]);
printf( "argv[1][j] = %c\n", argv[1][j]);
printf("Error.\n");
return 0;
}
}
}
Instead of the inner loop you could use the standard C function strchr. Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
int unique( const char *s )
{
while ( *s && !strchr( s + 1, *s ) ) ++s;
return *s == '\0';
}
int main(void)
{
char *s = "12345";
printf( "\"%s\" -> %d\n", s, unique( s ) );
s = "12341";
printf( "\"%s\" -> %d\n", s, unique( s ) );
return 0;
}
The program output is
"12345" -> 1
"12341" -> 0
You may call the function passing as an argument the command line argument argv[1]. For example
If ( !unique( argv[1] ) ) puts( "Error." );
Why A = K is because you are printing the i-th index printf("argv[1][i] = %c\n", argv[1][i]); when you are checking i+1th index if (argv[1][n] == argv[1][i + 1]). You are printing the wrong character that is checked with your if statement.
Also, be careful on that i+1 and your loop condition.
When I run this function I don't get a return value of 1 or 0. Im not sure why, I'm new to pointers and any type of help/tips would be greatly appreciated.
int isPalindrome (char * str)
{
char def[SIZE];
int length = strlen(str);
for(int count; count <= length; count++ ){
def[count] = str[count];
}
int c;
char *begin, *end, temp;
begin = str;
end = str;
for (c = 0; c < length - 1; c++)
end++;
for (c = 0; c < length/2; c++)
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
for(int count2; count2 <= length; count2++){
if(str[count2] != def[count2]){
return 0;
}
return 1;
}
}
The function is called with..
if(isPalindrome(arr) == 1)
printf ("\nIs a palindrome.\n\n");
To check if a string is a palindrome you create a reversed string, after first allocating enough room for all chars, by looping through the original one and changing the order. you can then use a strcmp to check if the reversed and original string are the same.
int isPalindrome (char * str)
{
int length = strlen(str);
char* reversed = malloc(sizeof(char)*length); //we allocate enough space for length chars
for(int i = 0; i < length; i++) {
reversed[i] = str[length-1-i]; //populate reversed with the chars in str but in the reversed order
}
if(strcmp(str,reversed) == 0) //strcmo(a,b) return 0 if they are equal
{
free(reversed); //deallocate the space for reversed
return 1;
}
free(reversed); //deallocate the space for reversed
return 0;
}
In these loops
for(int count; count <= length; count++ ){
def[count] = str[count];
}
and
for(int count2; count2 <= length; count2++){
if(str[count2] != def[count2]){
return 0;
}
return 1;
}
there are used uninitialized variables count and count2. So the function has undefined behavior.
Pay attention the the function is declared and defined incorrectly. It is too complicated and uses a magic number SIZE.
Also you should use the type size_t instead of the type int because the return type of the function strlen is size_t and in general an object of the type int can not accommodate an object of the type size_t.
There is no need to create an auxiliary array and change the original string to check whether the given string is a palindrome. Moreover the parameter shall be defined with the qualifier const. Otherwise you will be unable to check whether a string literal is a palindrome because modifying a string literal invokes undefined behavior.
Also if you are trying to use pointers then there is no need to use also indices in loops.
The function can be defined much simpler.
Here you are.
#include <stdio.h>
#include <string.h>
_Bool isPalindrome( const char *s )
{
const char *first = s, *last = s + strlen( s );
if ( first != last )
{
while ( first < --last && *first == *last ) ++first;
}
return !( first < last );
}
int main(void)
{
char *s1 = "121";
printf ( "\"%s\" is %s%s\n", s1, isPalindrome( s1 ) ? "a " : "not ", "palindrome." );
char *s2 = "1221";
printf ( "\"%s\" is %s%s\n", s2, isPalindrome( s2 ) ? "a " : "not ", "palindrome." );
return 0;
}
The program output is
"121" is a palindrome.
"1221" is a palindrome.
As you can see the function uses only pointers and neither index.
Your program has multiple problems. Lets see them one by one:
for(int count; count <= length; count++ ){
^^^^
def[count] = str[count];
}
You are not initialising count, you are just declaring it. Without any initial value count will just be some garbage. To fix this:
for(int count = 0; count <= length; count++ ){
def[count] = str[count];
}
Please note that older C versions require you to declare all variables in the beginning of a function block as far as I remember. So this is anyways wrong.
Next, your palindrome logic is incorrect. You are just swapping characters between begin and end.
All you have to do is check while iterating HALF THE STRING is whether the characters from the beginning equal to the end.
for (c = 0; c < length/2; c++)
{
// Check if "begin" equals to the current "end"
if (*begin != *end)
{
return 0;
}
// Move "begin" forward and "end" backwards
begin++;
end--;
}
Here is your complete function in working condition:
int isPalindrome(char* str)
{
int length = strlen(str);
int c;
char *begin, *end;
begin = str;
// Why use the below for loop when you can directly move end to the end?
end = str + length - 1;
// for (c = 0; c < length - 1; c++)
// end++;
for (c = 0; c < length / 2; c++) {
if (*begin != *end) {
return 0;
}
begin++;
end--;
}
return 1;
}
I need help to understand an issue with my C code. I am trying to find longest substring within a given string without character repetition. When run on the leetcode platform, the code below gives me an error for the String "amqpcsrumjjufpu":
Runtime Error Message: Line 17: index -3 out of bounds for type 'int [256]'
However, the same code works fine when I run it from my computer or any online editor. Please help me to understand this behaviour difference.
#include <stdio.h>
#include <string.h>
int lengthOfLongestSubstring(char* s) {
char *h = s;
int A[256] = {0};
int length = 0;
int temp = 0;
int max = 0;
int len = strlen(s);
for(int i = 0; i < len;i ++){
int A[256] = {0};
length = 0;
h = s + i;
for(int j = i; j < len-1; j++){
if (A[h[j]] == 1) {
break;
} else {
A[h[j]] = 1;
length +=1;
}
if (max < length) {
max = length;
}
}
}
return max;
}
int main() {
char *s = "amqpcsrumjjufpu";
int ret = lengthOfLongestSubstring(s);
printf("SAURABH: %d",ret);
}
It seems you are trying to write a function that finds the length of the longest substring of unique characters.
For starters the function should be declared like
size_t lengthOfLongestSubstring( const char *s );
^^^^^^ ^^^^^
These declarations in the outer scope of the function
int A[256] = {0};
//...
int temp = 0;
are redundant. The variables are not used in the function.
The type char can behave either as the type signed char or the type unsigned char. So in expressions like this A[h[j]] you have to cast explicitly the character used as index to the type unsigned char as for example
A[( unsigned char )h[j]]
The inner loop
for(int j=i;j<len-1;j++){
will not execute for strings that contain only one character. So it does not make sense as it is written.
This if statement
if (max < length) {
max = length ;
}
needs to be placed outside the inner loop.
The algorithm used by you can be implemented the following way
#include <stdio.h>
#include <limits.h>
size_t lengthOfLongestSubstring(const char *s)
{
size_t longest = 0;
for (; *s; ++s )
{
size_t n = 0;
unsigned char letters[UCHAR_MAX] = { 0 };
for ( const char *p = s; *p && !letters[(unsigned char)*p - 1]++; ++p) ++n;
if (longest < n) longest = n;
}
return longest;
}
int main( void )
{
char *s = "123145";
printf("The longest substring has %zu characters.\n",
lengthOfLongestSubstring(s));
return 0;
}
The program output is
The longest substring has 5 characters.
Your code crashed because you read data out of range, suppose your input string is amqpcsrumjjufpu its length is 15, in outer loop for i = 13 you do assigment
h = s + i; // h was updated to indicate to 13th element of s
and in inner loop for first iteration, you read this element (j == i == 13)
A[h[j]]
so, you try to read this element A[*(h+j)], but h indicates to 13th element of s, and now you try to add 13 to this value, you want to read 26th position of s, you are out of range of s string.
Thanks Everyone for responses. While Vlad's code worked for all the test cases, here is my code that also passed all the test cases after changes suggested by Vlad and rafix.
int lengthOfLongestSubstring(char* s) {
char *h = s;
int max = 0;
int len = strlen(s);
if (len == 1) {
return 1;
}
for(int i = 0; i < len;i ++){
int A[256] = {0};
int length = 0;
for(int j = i; j < len; j++){
if (A[(unsigned char)h[j]] == 1) {
break;
} else {
A[(unsigned char) h[j]] = 1;
length +=1;
}
}
if (max < length) {
max = length;
}
}
return max;
}
I have created a function that should find the numerical position of the first character of a substring in a larger string. I am having some problems with the output and I am not too sure why. These problems include -1 being returned every single time instead of the integer position of the substring. I have debugged and cannot trace where the function goes wrong.
This is how the function should perform: If my string is "The dog was fast" and I am searching for the substring "dog", the function should return 4. Thanks to chqrlie for help with the loop.
Here is the function:
int findSubString(char original[], char toFind[]) {
size_t i, j;
int originalLength = 0;
int toFindLength = 0;
originalLength = strlen(original) + 1;
toFindLength = strlen(toFind) + 1;
for (i = 0; i < toFindLength + 1; i++) {
for (j = 0; j < originalLength + 1; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
The function parameters cannot be modified, this is a requirement. Any help appreciated!
These statements inside the loops
if (toFind[j] == '\0') {
return i;
}
results in undefined behavior because the string toFind can be shorter than the string original.
The same is valid for this loop
if (original[i + j] != toFind[j]) {
break;
}
because i + j can be greater than the length of the string original.
And there is no need to scan all characters of the string original if you are going to find a substring inside it.
Also you should check whether the length of the string original is not less than the length of the string toFind.
If you want to find only the first character of the string toFind in the string original it is enough to use standard C function strchr. If you want to find the whole string toFind in the string original then you could use another C standard function strstr.
If you want to write the function yourself to find a string in other string then it can look for example the following way
I declared the function like
long long int findSubString( const char original[], const char toFind[] );
however you can write its declaration as you like for example like
int findSubString( char original[], char toFind[] );
But in this case you should declare function local variable success like
int success = -1;
and output the result using format specifier "%d" instead of "%lld".
Here you are.
#include <stdio.h>
#include <string.h>
#include <stddef.h>
long long int findSubString( const char original[], const char toFind[] )
{
size_t n = strlen( original );
size_t m = strlen( toFind );
long long int success = -1;
if ( !( n < m ) )
{
n = n - m + 1;
for ( size_t i = 0; success == -1 && i < n; i++ )
{
size_t j = 0;
while ( j < m && original[i+j] == toFind[j] ) j++;
if ( j == m ) success = i;
}
}
return success;
}
int main(void)
{
printf( "%lld\n", findSubString( "The dog was fast", "dog" ) );
return 0;
}
Its output is
4
Your loops are reversed. The outer loop should walk positions from zero to originalLength, inclusive; the nested loop should walk positions from zero to toFindLength, inclusive.
Both originalLength and toFindLength should be set to values returned by strlen, not strlen plus one, because null terminator position is not a good start.
Finally, you are returning -1 from inside the outer loop. This is too early - you should be returning -1 only after you are done with the outer loop as well.
Your loop counter tests are incorrect: wrong upper limit and the limits are off by one. Note that the tests are actually not necessary as you exit both loops when hitting the '\0' terminators.
Here is a simpler version:
int findSubString(const char *original, const char *toFind) {
for (size_t i = 0;; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
There is a small advantage at computing the string lengths to reduce the number of comparisons in pathological cases such as findSubString("aaaaaaaaaaa", "aaaaaaaaaaaa");
int findSubString(const char *original, const char *toFind) {
size_t originalLength = strlen(original);
size_t toFindLength = strlen(toFind);
if (toFindLength <= originalLength) {
for (size_t i = 0; i <= originalLength - toFindLength; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
}
}
return -1;
}
Suppose that we have a string "11222222345646". So how to print out subsequence 222222 in C.
I have a function here, but I think something incorrect. Can someone correct it for me?
int *longestsubstring(int a[], int n, int *length)
{
int location = 0;
length = 0;
int i, j;
for (i = 0, j = 0; i <= n-1, j < i; i++, j++)
{
if (a[i] != a[j])
{
if (i - j >= *length)
{
*length = i - j;
location = j;
}
j = i;
}
}
return &a[location];
}
Sorry,I don't really understand your question.
I just have a little code,and it can print the longest sub string,hope it can help.
/*breif : print the longest sub string*/
void printLongestSubString(const char * str,int length)
{
if(length <= 0)
return;
int i ;
int num1 = 0,num2 = 0;
int location = 0;
for(i = 0; i< length - 1; ++i)
{
if(str[i] == str[i+1])
++num2;//count the sub string ,may be not the longest,but we should try.
else
{
if(num2 >num1)//I use num1 store the sum longest of current sub string.
{ num1 = num2;location = i - num2;}
else
;//do nothing for short sub string.
num2 = 0;
}
}
for(i = location;str[i]== str[num1];++i)
printf("%c",str[i]);
printf("\n");
}
int main()
{
char * str = "1122222234566";
printLongestSubString(str,13);
return 0;
}
From your code it appears you want to return the longest sub-sequence (sub-string). Since I'm relearning C I thought I would give it a shot.
I've used strndup to extract the substring. I'm not sure how portable it is but I found an implementation if needed, just click on the link. It will allocate memory to store the new cstring so you have to remember to free the memory once finished with the substring. Following your argument list, the length of the sub-string is returned as the third argument of the extraction routine.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *extract_longest_subsequence(const char *str, size_t str_len, size_t *longest_len);
int main()
{
char str[] = "11222234555555564666666";
size_t substr_len = 0;
char *substr = extract_longest_subsequence(str, sizeof(str), &substr_len);
if (!substr)
{
printf("Error: NULL sub-string returned\n");
return 1;
}
printf("original string: %s, length: %zu\n", str, sizeof(str)-1);
printf("Longest sub-string: %s, length: %zu\n", substr, substr_len);
/* Have to remember to free the memory allocated by strndup */
free(substr);
return 0;
}
char *extract_longest_subsequence(const char *str, size_t str_len, size_t *longest_len)
{
if (str == NULL || str_len < 1 || longest_len == NULL)
return NULL;
size_t longest_start = 0;
*longest_len = 0;
size_t curr_len = 1;
size_t i = 0;
for (i = 1; i < str_len; ++i)
{
if (str[i-1] == str[i])
{
++curr_len;
}
else
{
if (curr_len > *longest_len)
{
longest_start = i - curr_len;
*longest_len = curr_len;
}
curr_len = 1;
}
}
/* strndup allocates memory for storing the substring */
return strndup(str + longest_start, *longest_len);
}
It looks like in your loop that j is supposed to be storing where the current "substring" starts, and i is the index of the character that you are currently looking at. In that case, you want to change
for (i = 0, j = 0; i <= n-1, j < i; i++, j++)
to
for (i = 0, j = 0; i <= n-1; i++)
That way, you are using i to store which character you're looking at, and the j = i line will "reset" which string of characters you are checking the length of.
Also, a few other things:
1) length = 0 should be *length = 0. You probably don't actually want to set the pointer to point to address 0x0.
2) That last line would return where your "largest substring" starts, but it doesn't truncate where the characters start to change (i.e. the resulting string isn't necessarily *length long). It can be intentional depending on use case, but figured I'd mention it in case it saves some grief.