I would like not just to know if the substring exists in a buffer, but to get the position it ends. I am doing a ftp and it will look for #filestart; to start copying the file and only will return the file when it finds #fileend;
I will send the first message with something like that: #filestart;len=50;
The first part is easy, cause I can use the strstr to find #filestart. But after that I would like to know the end of len, so I can "run" into the buffer, from that position forward until find the equal sign and start copying the lenght until the char ";" or '\0" be found. Sorry for my crap english, I am from Brasil and don't know that good english but I hope you all understand. I made a function to do that, but I would like to know if isn't there a standard one. Here is mine:
#define unsigned int B32U
#define char B8
B32U strsub(B8 *data, B8 *key) {
if (data && key) {
B8 *d = data;
B32U len = strlen(key), p = 0;
if (len > strlen(d))
return (0);
while (*d != '\0') {
if (*(d + len) != '\0') {
B32U x = 0;
while (x < len) {
if (key[x] == *d) {
*d++;
p++;
} else
break;
x++;
}
if (x == len)
return (p);
} else {
if (len == 1)
if (*d == key[0])
return (p);
B32 x = 0;
while (x < len) {
if (key[x] == *d) {
*d++;
p++;
} else
return (0);
x++;
}
return (p);
}
p++;
*d++;
}
}
return (0);
}
These defines are really problematic and the code does not compile:
#define unsigned int B32U
#define char B8
With the above definition, you do not define B32U as a preprocessor macro, but unsigned and it will expand to int B32U, not what you intended.
You should instead use typedef to define these types:
typedef unsigned int B32U;
typedef char B8;
Or not define these types at all and use standard types.
You can use strstr to write a simple function that returns a pointer to the end of the match or NULL is no match was found:
#include <string.h>
char *strstr_end(const char *s1, const char *s2) {
char *p = strstr(s1, s2);
if (p)
p += strlen(s2);
return p;
}
If you insist on returning the offset from the beginning of the string, you could return a signed type with value -1 if there is no match and the offset of the end if there is a match. ptrdiff_t is an good type for this:
#include <stddef.h>
#include <string.h>
ptrdiff_t strstr_endpos(const char *s1, const char *s2) {
char *p = strstr(s1, s2);
if (p)
return p - s1 + strlen(s2);
else
return -1;
}
To solve your problem you can use :
char *strrchr(const char *str, int c)
This function (which is in string.h) will return the adress of the last occurrence of the character c (';' or '\0' in your case) in the string str. However you only can find a char, not a string.
Related
Making my own version of strtrim in C and its working fine but I wonder why it's working if I declare 2 array of char, like this:
static int is_set(const char *set, char c)
{
char *s;
s = (char *)set;
while (*s)
{
if (*s == c)
return (1);
s++;
}
return (0);
}
static char *ft_strsub(char const *str, unsigned int start, unsigned int end)
{
char *res;
char *s;
size_t size;
int i;
size = end - start;
res = malloc(size + 1);
if (!res)
return (res);
s = (char *)str + start;
i = 0;
while (*s && end-- > start)
res[i++] = *s++;
res[i] = 0;
return (res);
}
char *ft_strtrim(char const *s1, char const *set)
{
char *start;
char *s;
s = (char *)s1;
while (*s && is_set(set, *s))
s++;
if (!*s)
return (s);
start = s;
while (*s)
s++;
while (is_set(set, *--s))
;
if (*s)
*++s = 0;
return (ft_strsub(start, 0, s1 - s));
}
int main(void)
{
char tst[] = " xxxtripouille";
char tst2[] = " x";
char * s = ft_strtrim(tst, tst2);
printf("%s\n", s);
free(s);
return (0);
}
But not if I pass directly a string directly in param. I'm getting bus error if I do this
int main(void)
{
/*char tst[] = " xxxtripouille";
char tst2[] = " x";*/
char * s = ft_strtrim(" xxxtripouille", " x");
printf("%s\n", s);
free(s);
return (0);
}
I must have missed something in my training ^^Thank's in advance !
EDIT:
Thank's for reply !
Thank you for your advice, I took care to write them down, I thank you again, and I also found out why it wasn't working, it's because I'm trying to close the string and as you told me: it's a read-only string;
char *ft_strtrim(char const *s1, char const *set)
{
char *start;
char *s;
s = (char *)s1;
while (*s && is_set(set, *s))
s++;
if (!*s)
return (ft_strdup(s));
start = s;
while (*s)
s++;
while (is_set(set, *--s))
;
if (*s)
++s;
return (ft_strsub(start, 0, s - start));
}
Here's a few lines of code you might consider to replace your is_set() function:
static int matchAny( const char *set, char c ) {
const char *s = set;
for( ; *s && *s != c; s++ )
; // just searching
return *s != '\0'; // true = match found
}
Don't "cast away" const-ness unnecessarily. Exploit the "conditional" segment of the for() loop. Return is also a conditional: "If not reaching the end of the string of 'bad' characters, then 'c' was 'matched' in that string.
If you get "trimming the front" working, perhaps a simple "reverse string" can be used to "trim the back end, too", then "reverse string" once more. Re-use code that works.
Seeing this function, it can be made even simpler:
static int matchAny( const char *set, const char c ) {
while( *set && *set != c )
set++; // just searching
return *set != '\0'; // true = match found
}
Often the best solution is to use fewer resources (like variables) but to use them wisely. Then, flaws have fewer places to hide.
At least this statement does not make a sense
return (ft_strsub(start, 0, s1 - s));
because there can be passed a negative value s1 - s that will be converted to a very big positive value in the function ft_strsub because the corresponding parameter has an unsigned integer type.
Pay attention to that the compiler can issue a message that you are discarding the qualifier const as for example
char *s;
s = (char *)s1;
Also the function can return a pointer that does not point to a dynamically allocated array that you are tries to free with the function free
if (!*s)
return (s);
//...
free(s);
I have created a function for strend, which basically returns 1 if string t is present at the end of string s, however it never returns 1:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int strend(char *s, char *t) {
int p;
for (p = 0; p < strlen(s) - strlen(t); p++) {
*s++;
}
printf("%s\n%s\n", s, t);
if (s == t)
return 1;
return 0;
}
int main(void) {
int bool = strend("Hello", "ello");
printf("%i\n", bool);
return 0;
}
This gives me an output of:
ello
ello
0
So technically I should get 1. I assume the comparison using pointers is not used in this way?
You need to review your basic knowledge of C strings. There are lots of standard string functions in string.h that can help you with this test.
The basic problem is that the test s == t is valid, but you are comparing memory addresses here. You can see that is valid if you change the strings to test to
char test[] = "Hello";
int bool = strend_(test, test+1);
where test obviously is the same as your "Hello", and similarly, test+1 is the same as "ello" (try it by printing them). This correctly returns 1 with your routine.
In addition, I get two warnings:
on *s++; "warning: expression result unused [-Wunused-value]": you increment s but also ask what character is at that position through *s; and you don't use that information.
Fix by removing the * there.
on p < strlen(s) ..; "warning: comparison of integers of different signs: 'int' and 'unsigned long'", because strlen does not return a signed integer but an unsigned one (apparently, my header uses unsigned long).
Fix by declaring p as unsigned long, or even better, size_t.
Your entire routine can be condensed to a simple
int strend (char *s, char *t)
{
if (strlen(s) >= strlen(t) && !strcmp (s+strlen(s)-strlen(t),t))
return 1;
return 0;
}
It's not worth the trouble to cache the result of those four strlen calls into 2 temporary variables; a good compiler will work it out and do that for you. (A quick glance to the assembly output of the compiler I'm using – clang – shows it does, even with the default optimization settings.)
A slightly modified test, based on #M.M.'s comment:
int strend (char *s, char *t)
{
if (strlen(s) < strlen(t)) return 0;
return !strcmp (s+strlen(s)-strlen(t),t);
}
but attempting to optimize it this way is not as easy parsed as the routine above, and its assembly is ever so slightly "wordy" as well. Personally, I'd go for the more humanly readable version.
Use strcmp(3)
if (strcmp(s, t) == 0) return 1;
This actually compares the contents of the memory pointed to by s and t rather than their addresses.
Your code is broken in multiple ways:
The initial loop is a very cumbersome way to advance p by the difference of lengths if positive.
Once you have pointers at the same distance from the end of both strings, You should compare the characters with strcmp() (or memcmp() if you can first exclude the case of strlen(s) < strlen(t).
Comparing the pointers obtained after the loop will only work if t points inside the string pointed to by s, a special case that may or may not be produced by the compiler for the specific call in main: strend("Hello", "ello");.
Here is a modified version:
#include <string.h>
int strend(const char *str1, const char *str2) {
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
return len1 >= len2 && !memcmp(str1 + len1 - len2, str2, len2);
}
I corrected/modified your code, here is the code,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#pragma warning(disable:4996)
int strend(char *s, char *t)
{
int p,flag=0,count=0;//count will be the starting index for *t
p = strlen(s) - strlen(t);//this will be the starting index for *s
while(count<strlen(t))
{
if (*(s+p) == *(t+count))
{
flag = 1;
count++;
p++;
continue;
}
else
{
flag = 0;
break;
}
}
return flag;
}
int main(void)
{
int flag = strend("Hello", "ello");
printf("%i\n", flag);
return 0;
}
This code works too.
#include <stdio.h>
#include <string.h>
int strend (char *s1, char *s2);
void main ()
{
char str1[20] = "somethings";
char str2[20] = "things";
int f;
f = strend (str1,str2);
if (f==1)
printf ("1");
else
printf ("0");
}
int strend (char *str1, char *str2)
{
int l = strlen(str1) - strlen(str2);
str1 = str1 + l;
int d = strcmp(str1,str2);
if (d == 0)
return 1;
else
return 0;
}
this code works well.
int strend(char *s, char *t){
while(*t & *s){
if(*t == *s){
t++;
}
s++;
}
return *t==*s;
}
Folks, need to search through a character array and replace any occurrence of '+','/',or'=' with '%2B','%2F', and '%2F' respectively
base64output variable looks like
FtCPpza+Z0FASDFvfgtoCZg5zRI=
code
char *signature = replace_char(base64output, "+", "%2B");
signature = replace_char(signature, "/", "%2F");
signature = replace_char(signature, "=", "%3B");
char replace_char (char *s, char find, char replace) {
while (*s != 0) {
if (*s == find)
*s = replace;
s++;
}
return s;
}
(Errors out with)
s.c:266: warning: initialization makes pointer from integer without a cast
What am i doing wrong? Thanks!
If the issue is that you have garbage in your signature variable:
void replace_char(...) is incompatible with signature = replace_char(...)
Edit:
Oh I didn't see... This is not going to work since you're trying to replace a char by an array of chars with no memory allocation whatsoever.
You need to allocate a new memory chunk (malloc) big enough to hold the new string, then copy the source 's' to the destination, replacing 'c' by 'replace' when needed.
The prototype should be:
char *replace_char(char *s, char c, char *replace);
1.
for char use '' single quotes
for char* use "" double quotes
2.
The function does include the return keyword, therefore it does not return what you'd expect
3.
These webpages have examples on string replacement
http://www.cplusplus.com/reference/cstring/strstr/
What is the function to replace string in C?
You could go for some length discussing various ways to do this.
Replacing a single char is simple - loop through, if match, replace old with new, etc.
The problem here is that the length of the "new" part is longer than the length of the old one.
One way would be to determine the length of the new string (by counting chars), and either (1) try to do it in place, or (2) allocate a new string.
Here's an idea for #1:
int replace(char *buffer, size_t size, char old, const char *newstring)
{
size_t newlen = strlen(newstring);
char *p, *q;
size_t targetlen = 0;
// First get the final length
//
p = buffer;
while (*p)
{
if (*p == old)
targetlen += newlen;
else
targetlen++;
++p;
}
// Account for null terminator
//
targetlen++;
// Make sure there's enough space
//
if (targetlen > size)
return -1;
// Now we copy characters. We'll start at the end and
// work our way backwards.
//
p = buffer + strlen(buffer);
q = buffer + targetlen;
while (targetlen)
{
if (*p == old)
{
q -= newlen;
memcpy(q, newstring, newlen);
targetlen -= newlen;
--p;
}
else
{
*--q = *p--;
--targetlen;
}
}
return 0;
}
Then you could use it this way (here's a quick test I did):
char buf[4096] = "hello world";
if (replace(buf, sizeof(buf), 'o', "oooo"))
{
fprintf(stderr, "Not enough space\n");
}
else
{
puts(buf);
}
your replace_char signature returns void
void replace_char (char *s, char find, char replace)
But, when the linker tries to resolve the following
signature = replace_char(signature, "=", '%3B');
It doesn't find any function that's called replace_char and returns int (int is the default if there's no prototype).
Change the replace_char function prototype to match the statement.
EDIT:
The warning states that your function returns char, but you use it as a char *
also, your function doesn't return anything, do you need to return something ?
It looks like you don't really understand the code that you're working with.
Fixing errors and warnings without understanding exactly what you need to do is worthless..
fix like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace_char (char *str, char find, char *replace) {
char *ret=str;
char *wk, *s;
wk = s = strdup(str);
while (*s != 0) {
if (*s == find){
while(*replace)
*str++ = *replace++;
++s;
} else
*str++ = *s++;
}
*str = '\0';
free(wk);
return ret;
}
int main(void){
char base64output[4096] = "FtCPpza+Z0FASDFvfgtoCZg5zRI=";
char *signature = replace_char(base64output, '+', "%2B");
signature = replace_char(signature, '/', "%2F");
signature = replace_char(signature, '=', "%3B");
printf("%s\n", base64output);
return 0;
}
below is a code that ACTUALLY WORKS !!!!
Ammar Hourani
char * replace_char(char * input, char find, char replace)
{
char * output = (char*)malloc(strlen(input));
for (int i = 0; i < strlen(input); i++)
{
if (input[i] == find) output[i] = replace;
else output[i] = input[i];
}
output[strlen(input)] = '\0';
return output;
}
Im trying to copy part of a string to another string using pointers. My resulting string starts to copy at the correct place though it doesn't stop after exceeding the count. Also the string isn't copy from the source string rather than from the result parameter
#include <stdio.h>
char *getSub(const char *orig, int start, int count, char *res);
int main(void)
{
const char orig[] = "one two three";
char res[] = "123456789012345678";
printf("%s\n",getSub(orig, 4, 3, res));
return 0;
}
char *getSub(const char *orig, int start, int count, char *res)
{
const char *sCopy = orig;
while (*orig)
{
if (start >= (orig - sCopy)) && (res-sCopy < count))
{
*res++ = *orig++;
}
else
*orig++;
}
return res;
}
The big mistake is that you're calculating the difference of two unrelated pointers, res - sCopy (I suppose sourceCopy is also sCopy in the real code, or the other way round). Calculating the difference of pointers is only meaningful if both pointers point into (or one past the end of) the same array. As written, whether anything gets copied at all depends on the arbitrary locations of the two arrays.
if (start >= (orig - sourceCopy)) && (res-sCopy < c))
{
*res++ = *orig++;
}
else
*orig++;
anyway, that doesn't count how many characters are copied if any are copied at all.
Another mistake is that you don't 0-terminate the copy.
A correct implementation would be
char *getSub(const char *orig, int start, int count, char *res)
{
char *from = orig, *to = res;
// check whether the starting position is within orig
for( ; start > 0; --start, ++from)
{
if (*from == 0)
{
res[0] = 0;
return res;
}
}
// copy up to count characters from from to to
for( ; count > 0 && *from; --count)
{
*to++ = *from++;
}
// 0-terminate
*to = 0;
// return start of copy, change to return to if end should be returned
return res;
}
There are at least two problems with your code.
res - sCopy makes no sense because they are pointing at different objects.
You haven't null-terminated the destination string.
#include <string.h>
char *getSub(const char *orig, int start, int count, char *res){
int i,j,len = strlen(orig), limit = start + count;
if(res == NULL) return NULL;
if(start >= len || start < 0 || orig == NULL){
*res = '\0';
return res;
}
for(j=0,i=start;i<len && i < limit;++i){
res[j++]=orig[i];
}
res[j]='\0';
return res;
}
I am really new to C.
I want to use the strpos function but it is telling me it doesnt exist?
Here a complete snippet code to solve you problem.
PS: Isn't too late to help. ;)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NOT_FOUND -1
int main (){
int pos = NOT_FOUND;
if ( (pos = strpos( "subsstring", "string")) != NOT_FOUND )
printf("found at %d\n", pos);
else
printf("not found!\n");
return 0;
}
int strpos(const char *haystack, const char *needle)
{
const char *p = strstr(haystack, needle);
if (p)
return p - haystack;
return NOT_FOUND;
}
Edit: Answering Can Vural question:
No. I really think that it would be as it is. At structured programming paradigm, it's a common practice to use the scope structure as first parameter on every function that belongs to the structure's scope itself. The strstr function defined at string.h follow the same approach.
On OOP you have haystack.indexOf( needle ). At structured programming, you have indexOf( haystack, needle ).
The function you are looking for might be either strstr or strchr. You then need to include string.h. There is no strpos in the POSIX interface.
Yes. It's called strstr, related to strpos like (pseudo-code):
strpos(str, target) {
res = strstr(str, target);
if (res == NULL) return false;
else return res - str;
}
I have written strpos() function from scratch with position feature(Like PHP's strpos() function). Return value will be starting position of searched string. Enjoy! :)
In this example code output will be 12
#include <stdio.h>
#include <string.h>
int strpos(char *haystack, char *needle, int pos);
int main(){
printf("%d",strpos("abcdefabcdefabcdef asdfgavcabcddd","abc",10));
return 0;
}
int strpos(char *haystack, char *needle, int pos){
int i,j,check,result = -1;
int len_needle=strlen(needle);
int len_haystack=strlen(haystack);
i = pos;
if (len_needle>len_haystack || *needle==NULL || i>(len_haystack-1)) return result;
for(;i<len_haystack;i++){
check = 0;
for(j=0;j<len_needle;j++){
if(haystack[i+j]==needle[j]){
check++;
}
}
if(check==len_needle){
result = i;
break;
}
}
return result;
}
This is in response to Miere and Can Vural. I can't add comments yet so will add this as an answer.
Shouldn't it be strpos("string", "substring") – Can Vural
At structured programming, you have indexOf( haystack, needle ). Miere
In your code, you have:
int strpos(char *haystack, char *needle)
but you also have:
(pos = strpos( "subsstring", "string"))
I fully agree with the "int strpos(char *haystack, char *needle)" where the string to be searched comes first and the string to search FOR comes second. But to me, "subsstring" (in the context of "one is a substring and one is a string"), "subsstring" implies that IT is the shorter of the two and that you're trying to find "substring" in "string."
So the one part:
(pos = strpos( "subsstring", "string"))
should be:
(pos = strpos( "string" /*that which is being searched within*/, "substring" /*that which is being searched for in the previous parameter*/))
which would be the same as:
(pos = strpos( "haystack", "needle"))
Edit: One of the C comments above wasn't closed properly due to a typo.
There is no function strpos defined in the Standard C library nor in the POSIX Standard. PHP has a function strpos with this definition:
strpos(string $haystack, string $needle, int $offset = 0): int|false
This function locates a substring needle inside a string haystack and returns the offset from the beginning of the string haystack.
C has function strstr that can be used for this purpose and returns a pointer to the substring or NULL if no match is found:
char *strstr(const char *haystack, const char *needle);
Here is an implementation for a C equivalent of strpos relying on strstr for the dirty work. Note however that the name strpos is reserved for future functions in <string.h>:
#include <string.h>
int strpos(const char *haystack, const char *needle, int offset) {
char *p;
size_t len, pos;
len = strlen(haystack);
pos = 0;
if (offset < 0) {
if (len > INT_MAX || offset < -(int)len)
pos = len + offset;
} else {
if (len <= INT_MAX && offset > len)
return NULL;
pos = offset;
}
p = strstr(haystack + pos, needle);
if (p != NULL && p - haystack <= INT_MAX)
return (int)(p - haystack);
else
return -1;
}