Hello I am new in c and ı have homework about tcp program and one poin in this project I cant pass can anywone help me please
StartsWithDEL() this function catch DEL user.txt like return true
trim() like trim and give only file name user.txt
BUT when I write client line DEL user.txt is not going delete
if (StartsWithDEL(line,"DEL") == 1)
{
char *deltoken = strtok(line, "DEL");
char *itemDeleting = trim(deltoken);
//in this section I cach file name but cant delete it
remove(itemDeleting);
send(client, "\n" ,strlen("\n"),0);
}
Your call to strtok() in incorrect. The second argument is a string or allowed token delimiters, which in your case a . If you call it with "DEL", it will overwrite the D with \0 and deltoken will point to that empty string.
If you choose to use strtok() then:
char* token = strtok( line, " " ) ;
if( strcmp( token, "DEL" ) == 0 )
{
char* itemDeleting = strtok( NULL, " " ) ;
remove(itemDeleting);
send(client, "\n" ,strlen("\n"),0);
}
However if is simpler to avoid the complexity of strtok(), and the fact that it modifies line by inserting nuls makes it undesirable in many cases. The code above also won't work if a filename may contains spaces.
There are many alternative solutions, for example:
size_t delimiter_index = strcspn( line, " " ) ;
if( strncmp( line, "DEL", delimiter_index ) == 0 )
{
char* itemDeleting = &line[delimiter_index] ;
while( *itemDeleting == 0 && *itemDeleting != '\0' ) itemDeleting++ ;
remove(itemDeleting);
send(client, "\n" ,strlen("\n"),0);
}
Since I have no idea what StartsWithDEL() or trim() so I have avoided them.
Related
The format that I want to match the string to is "from:<%s>" or "FROM:<%s>". The %s can be any length of characters representing an email address.
I have been using sscanf(input, "%*[fromFROM:<]%[#:-,.A-Za-z0-9]>", output). But it doesn't catch the case where the last ">" is missing. Is there a clean way to check if the input string is correctly formatted?
You can't directly tell whether trailing literal characters in a format string are matched; there's no direct way for sscanf()) to report their absence. However, there are a couple of tricks that'll do the job:
Option 1:
int n = 0;
if (sscanf("%*[fromFROM:<]%[#:-,.A-Za-z0-9]>%n", email, &n) != 1)
…error…
else if (n == 0)
…missing >…
Option 2:
char c = '\0';
if (sscanf("%*[fromFROM:<]%[#:-,.A-Za-z0-9]%c", email, &c) != 2)
…error — malformed prefix or > missing…
else if (c != '>')
…error — something other than > after email address…
Note that the 'from' scan-set will match ROFF or MorfROM or <FROM:morf as a prefix to the email address. That's probably too generous. Indeed, it would match: from:<foofoomoo of from:<foofoomoo#example.com>, which is a much more serious problem, especially as you throw the whole of the matched material away. You should probably capture the value and be more specific:
char c = '\0';
char from[5];
if (sscanf("%4[fromFROM]:<%[#:-,.A-Za-z0-9]%[>]", from, email, &c) != 3)
…error…
else if (strcasecmp(from, "FROM") != 0)
…not from…
else if (c != '>')
…missing >…
or you can compare using strcmp() with from and FROM if that's what you want. The options here are legion. Be aware that strcasecmp() is a POSIX-specific function; Microsoft provides the equivalent stricmp().
Use "%n". It records the offset of the scan of input[], if scanning got that far.
Use it to:
Detect scan success that include the >.
Detect Extra junk.
A check of the return value of sscanf() is not needed.
Also use a width limit.
char output[100];
int n = 0;
// sscanf(input, "%*[fromFROM:<]%[#:-,.A-Za-z0-9]>", output);
sscanf(input, "%*[fromFROM]:<%99[#:-,.A-Za-z0-9]>%n", output);
// ^^ width ^^
if (n == 0 || input[n] != '\0') {
puts("Error, scan incomplete or extra junk
} else [
puts("Success");
}
If trailing white-space, like a '\n', is OK, use " %n".
Regarding the first part of the string, if you want to accept only FROM:< or from:< , then you can simply use the function strncmp with both possibilities. Note, however, that this means that for example From:< will not be accepted. In your question, you implied that this is how you want your program to behave, but I'm not sure if this really is the case.
Generally, I wouldn't recommend using the function sscanf for such a complex task, because that function is not very flexible. Also, in ISO C, it is not guaranteed that character ranges are supported when using the %[] format specifier (although most common platforms probably do support it). Therefore, I would recommend checking the individual parts of the string "manually":
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
bool is_valid_string( const char *line )
{
const char *p;
//verify that string starts with "from:<" or "FROM:<"
if (
strncmp( line, "from:<", 6 ) != 0
&&
strncmp( line, "FROM:<", 6 ) != 0
)
{
return false;
}
//verify that there are no invalid characters before the `>`
for ( p = line + 6; *p != '>'; p++ )
{
if ( *p == '\0' )
return false;
if ( isalpha( (unsigned char)*p ) )
continue;
if ( isdigit( (unsigned char)*p ) )
continue;
if ( strchr( "#:-,.", *p) != NULL )
continue;
return false;
}
//jump past the '>' character
p++;
//verify that we are now at the end of the string
if ( *p != '\0' )
return false;
return true;
}
int main( void )
{
char line[200];
//read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
printf( "Input failure!\n" );
exit( EXIT_FAILURE );
}
//remove newline character
line[strcspn(line,"\n")] = '\0';
//call function and print result
if ( is_valid_string ( line ) )
printf( "VALID\n" );
else
printf( "INVALID\n" );
}
This program has the following output:
This is an invalid string.
INVALID
from:<john.doe#example.com
INVALID
from:<john.doe#example.com>
VALID
FROM:<john.doe#example.com
INVALID
FROM:<john.doe#example.com>
VALID
FROM:<john.doe#example!!!!.com>
INVALID
FROM:<john.doe#example.com>invalid
INVALID
I was working on file inputs. I wanted to store each line as a string in array. For example: if the file has lines:
This is line 1.
This is line 2.
This is line 3.
The string should contain:
char str[][] = {"This is line 1.", "This is line 2.", "This is line 3."};
When I was trying out with extra spaces:
This is line 1.
This is line 2.
This is line 3.
The output was in the same format.
I want to delete those extra empty lines from my array of sentences, so that the output is same as before. How should I do that?
[EDIT] I am using following loop to enter sentences from file to the array:
while (fgets(str[i], LINE_SIZE, fp) != NULL)
{
str[i][strlen(str[i]) - 1] = '\0';
i++;
}
You should use an intermediate one-dimensional character array in the call of fgets like for example
for ( char line[LINE_SIZE]; fgets( line, LINE_SIZE, fp) != NULL; )
{
if ( line[0] != '\n' )
{
line[ strcspn( line, "\n" ) ] = '\0';
strcpy( str[i++], line );
}
}
If a line can contain blanks you can change the condition of the if statement the following way
for ( char line[LINE_SIZE]; fgets( line, LINE_SIZE, fp) != NULL; )
{
size_t n = strspn( line, " \t" );
if ( line[n] != '\n' && line[n] != '\0' )
{
line[ n + strcspn( line + n, "\n" ) ] = '\0';
strcpy( str[i++], line );
}
}
In the above code snippet you can substitute this statement
strcpy( str[i++], line );
for this statement if you want that the string would not contain leading spaces.
strcpy( str[i++], line + n );
Hi I am new to C and I want the user to type something like inspect 2 to show a value of an array at position 2 in that example.
I cant get it to work
char input[20];
scanf("%s", input);
if (strcmp(strtok(input, " "), "inspect") == 0) {
char str[20];
int idx;
printf("input was %s", input);
idx = sscanf(input, "%s %d", str, &idx);
}
it always prints input was inspect but the following space and number are not read?
What would be the right way to check if the user typed "inspect" and get the index he typed afterwards like I am trying to do?
thank you
You have few choices, and you want to choose one and not mix them up.
For reading the input, consider using the fgets. Much safer, with fewer exceptions to deal with. I've listed the equivalent sscanf, but it's much harder to use. They will both bring in a complete line to 'input'. Notice that the fgets will also include the trailing new line.
// make buffer large enough.
char input[255] ;
if ( fgets(input, sizeof(input), stdin) != NULL ) {
...
}
// OR
if ( sscanf("%19[^\n]", input) = 1 ) {
} ;
For parsing: few options to parse the input` string.
Between the option, I would vote for the sscanf, as it provides the most validation and protection against bad input, overflow, etc. The strcmp(strtok(...)) can easily result in SEGV errors, when strtok returns NULL.
Using sscanf
if ( sscanf(input, "inspect %d", &idx) ==1 ) {
... Show Element idx
} ;
Using strtok/strcmp
if ( strcmp(strtok(input, " "), "inspect") == 0 ) {
if ( sscanf("%d", strtok(NULL, " "), &idx) == 1 ) {
.. Show element idx
} ;
} ;
Using strtol
if ( strcmp(strtok(input, " "), "inspect") == 0 ) {
char *stptr = strtok(input, " "), *endptr = NULL ;
idx = strtol(stptr, &endptr, 10) ;
if ( endptr != stptr ) {
.. Show element idx
} ;
} ;
I'm trying to do, a program that prints a string like this
char str[] = "This is a test string";
And then get this output
This
is
a
test
string
All this without using neither loop nor recursion. It is possible to do this?
As noted in the comments to this answer, goto is just a bad replacement for for, while, etc. Technically, it is a loop, so writing the program without looping is pretty much impossible.
Furthermore, as others have mentioned, printf and similar screen I/O functions most probably also uses a loop, so "All this without using loop nor recursion [...]" should be pretty hard.
Writing the "printing each word on a seperate line" part as a general solution1 could be done using the goto keyword, though. The following program replaces every occurence of ' ' with a \n and prints the string afterwards:
size_t i = 0;
loop_beg:
if (!str[i])
goto loop_end;
if (str[i] == ' ')
str[i] = '\n';
++i;
goto loop_beg;
loop_end:
printf("%s\n", str);
Note: this probably compiles down to a loop at the Assembly level and is then roughly equivalent to the for-loop construct in C but I'll ignore that.
Related to that, you should read (or at least skim) Edsger Dijsktra's (Dutch guy, invented semaphores, co-wrote the OS "THE") "Go To Statement Considered Harmful".
1 to just print every word of this particular string on one line each neither of this is required, obviously.
you can use strtok for this but it is implemented with the help of loop and its pretty neat
char str[] ="This is a test string";
char * pch;
pch = strtok (str," ");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " "); <-- delimiter to seperate the string
}
#include <stdio.h>
int main(void)
{
char str[] = " this is a string";
char *ptr = str;
bool init = 0;
int n = 0;
BlackLabel:
if( *ptr == '\0' )
goto exit;
n++;
if( *ptr == ' ' )
n = 0;
if( n == 1 )
{
if( init )
{
putc('\n',stdout);
}
}
if( n > 0 )
{
init = 1;
printf("%c",*ptr);
}
*ptr++;
goto BlackLabel;
exit:
putc('\n',stdout);
return 0;
}
I propose to replace space with new line indicator.
public string f(string input)
{
str = str.Replace(" ", "\n");
return str;
}
This fuction will return text with each word one below another.
EDIT:
Note that this will be always used with loops. Even if not called directly, your application just must to go throught all characters in range.
Edit: Ok, so for some reason I thought the scanf line would read in the entire line as a string (multiple arguments). Brain must really be fried. Thank you all for your help.
I am trying to place some chars into an array. Here is how the code looks.
Edit: adding more code to hopefully shed more light in the problem
Edit2: can I treat the char pointer "message" like a string in this function?
//in main...
printf( "Enter a command> " );
scanf( "%s", buf );
message = convertMessage( buf );
//....
char* convertMessage( char *message ){
char *convMess = calloc( 50, sizeof(char) );
char *tok = strtok( message, " ," );
if( convMess == NULL ){
perror( "memory error" );
exit(-5);
}
if( strcmp( tok, "get" ) == 0 ){
tok = strtok( NULL, " ," );
if( strcmp( tok, "lname" ) == 0 ){
convMess[0] = '1'; // seg faults on this line
convMess[1] = ' ';
strcat( convMess, tok );
return convMess;
}
else if( //...
//...and so on
//output from gdb
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400e5d in convertMessage (
message=0x7fffffffbfa0 "get") at client.c:135
135 if( strcmp( tok, "lname" ) == 0 ){
(gdb) quit
I know I am probably misunderstanding something very simple but I have been working on this code for so long I think my mind has fried. Also, I have checked the online references and the code on cplusplus.com/reference looks the same as what I have.
Thank you for your help.
You might be compiling for a 64-bit platform without including stdlib.h - if there's no declaration/prototype for calloc() the compiler will truncate the returned pointer to an int (assuming an int is 32 bits).
Use appropriate compiler options to have the compiler generate a warning or error for this kind of thing.
From you posting I see the app segfaults in line135:
if( strcmp( tok, "lname" ) == 0 ){
Most propably you are passing in tok, with tok being NULL.
You might want to check the value of tok against NULL after having it assigned in line 134:
tok = strtok( NULL, " ," );
before passing it to strcmp(), like so for example:
tok = strtok( NULL, " ," );
if (tok != NULL) {
if (strcmp( tok, "lname" ) == 0 ) {
...
}