Related
I think there are some problems related to the memory and the heap corruption that don't allow my program to run properly (mainly because of some bug inside of it). The program just stops running, or crashes after its quit.
I'm trying to learn how trees work and for my case I have to write a cross-referencer that reads all the words in a document (in my case, the input line), and for each word, a list of the line numbers on which it occurs. For example:
foo
bar bar
foo bar
Should produce as output:
2 foo: [1, 3]
2 bar: [2, 3]
where the numbers inside the [] are the lines where our words are found.
There are 2 main issues with my code:
it only prints 1 inside the brackets, as if the program never checks the newline
if I try to run more than 10 lines of input it crashes. Without gdb it allows me to output all the lines I want, and won't crash until it reaches the 10 lines:
t
t
t
t
t
quit
5 t: [1, 1, 1, 1, 1]
When I run it with gdb, instead, it gives me this:
(gdb) r
Starting program: C:\...\6.exe
[New Thread 15276.0x14fc]
t
t
t
warning: HEAP[6.exe]:
warning: Heap block at 000001E191B97CA0 modified at 000001E191B97CB6 past requested size of 6
Thread 1 received signal SIGTRAP, Trace/breakpoint trap.
0x00007ff981f969ff in ntdll!RtlRegisterSecureMemoryCacheCallback () from C:\WINDOWS\SYSTEM32\ntdll.dl
(gdb) bt
#0 0x00007ff981f969ff in ntdll!RtlRegisterSecureMemoryCacheCallback ()
from C:\WINDOWS\SYSTEM32\ntdll.dll
#1 0x00007ff981f9288a in ntdll!RtlZeroHeap () from C:\WINDOWS\SYSTEM32\ntdll.dll
#2 0x00007ff981f61357 in ntdll!EtwLogTraceEvent () from C:\WINDOWS\SYSTEM32\ntdll.dll
#3 0x00007ff981f95839 in ntdll!RtlRegisterSecureMemoryCacheCallback ()
from C:\WINDOWS\SYSTEM32\ntdll.dll
#4 0x00007ff981f4de29 in ntdll!EtwLogTraceEvent () from C:\WINDOWS\SYSTEM32\ntdll.dll
#5 0x00007ff981ed24b7 in ntdll!RtlReAllocateHeap () from C:\WINDOWS\SYSTEM32\ntdll.dll
#6 0x00007ff981ed237a in ntdll!RtlReAllocateHeap () from C:\WINDOWS\SYSTEM32\ntdll.dll
#7 0x00007ff97fb71a89 in ucrtbase!_realloc_base () from C:\WINDOWS\System32\ucrtbase.dll
#8 0x00007ff71ff81bbe in addtree ()
#9 0x00007ff71ff81a4e in main ()
I didn't even type quit (the word to break the loop) and it just stopped by giving me this warning.
I don't know how to fix this, because probably I am forgetting to free something (there is some heap allocation), but I have no idea on where the problem may be.
This is the code:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 100
#define MAXWORD 100
#define IS_NOISE_WORD(word) \
(strcmp(word, "a") == 0 || \
strcmp(word, "an") == 0 || \
strcmp(word, "the") == 0 || \
strcmp(word, "and") == 0 || \
strcmp(word, "or") == 0 || \
strcmp(word, "in") == 0 || \
strcmp(word, "of") == 0 || \
strcmp(word, "to") == 0 || \
strcmp(word, "is") == 0 || \
strcmp(word, "are") == 0 || \
strcmp(word, "was") == 0 || \
strcmp(word, "were") == 0 || \
strcmp(word, "be") == 0 || \
strcmp(word, "been") == 0 || \
strcmp(word, "being") == 0 || \
strcmp(word, "have") == 0 || \
strcmp(word, "has") == 0 || \
strcmp(word, "had") == 0 || \
strcmp(word, "having") == 0)
/* etc. */
#define IS_NOT_NOISE_WORD(word) (!IS_NOISE_WORD(word))
/* the tree node */
struct tnode {
char *word; /* points to the text */
int count; /* number of occurrences */
int *lines; /* lines where the word occurs */
struct tnode *left; /* left child */
struct tnode *right; /* right child */
};
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */
/* char *strdup(char *); */
int getword(char *, int);
struct tnode *addtree(struct tnode *, char *, int);
void tfree(struct tnode *);
void treeprint(struct tnode *);
/* word frequency count */
int main(int argc, char *argv[])
{
struct tnode *root = NULL;
char word[MAXWORD];
int n = 1; /* number of lines */
while (getword(word, MAXWORD) != EOF)
{
if (word[0] == '\n')
n++;
/* if there is a word and it's not a noise */
if (isalpha(word[0]) && IS_NOT_NOISE_WORD(word) && strcmp(word, "quit") != 0 && strcmp(word, "exit") != 0)
root = addtree(root, word, n);
if (!strcmp(word, "quit") || !strcmp(word, "exit"))
break;
}
treeprint(root);
tfree(root);
return 0;
}
/* addtree: add a node with the word w at line l, at or below p */
struct tnode *addtree(struct tnode *p, char *w, int l)
{
int cond;
/* a new word has arrived */
if (p == NULL)
{
/* make a new node */
p = malloc(sizeof(struct tnode));
p->word = strdup(w);
p->count = 1;
p->lines = calloc(p->count + 1, sizeof(int));
p->lines[p->count - 1] = l;
p->left = p->right = NULL;
}
else {
cond = strcmp(w, p->word);
if (cond == 0) {
/* repeated word */
p->count++;
p->lines = realloc(p->lines, p->count + 1 * sizeof(int));
p->lines[p->count - 1] = l;
}
else if (cond < 0) {
/* less than into left subtree */
p->left = addtree(p->left, w, l);
}
else {
/* greater than into right subtree */
p->right = addtree(p->right, w, l);
}
}
return p;
}
/* tfree: free a tnode */
void tfree(struct tnode *p)
{
if (p == NULL)
return;
tfree(p->left);
tfree(p->right);
free(p);
if (p->word != NULL) {
free(p->word);
p->word = NULL;
}
if (p->lines != NULL) {
free(p->lines);
p->lines = NULL;
}
}
/* treeprint: in-order print of tree p */
void treeprint(struct tnode *p)
{
int i;
if (p != NULL) {
treeprint(p->left);
printf("%4d %s: [%d", p->count, p->word, p->lines[0]);
for (i = 1; i < p->count; i++)
printf(", %d", p->lines[i]);
printf("]\n");
treeprint(p->right);
}
}
/* getword: get next word or character from input */
int getword(char *word, int lim)
{
char *w = word;
int c, getch(void);
void ungetch(int);
int in_comment = 0; /* 1 if inside a comment */
int in_pp_line = 0; /* 1 if inside a preprocessor line */
int in_string = 0; /* 1 if inside a string */
/* skip spaces */
while (isspace(c = getch()))
;
if (c != EOF)
*w++ = c;
/* not underscore, pp line, comment, string */
if (!isalpha(c) && c != '_' && c != '\"' && c != '#' && c != '/') {
*w = '\0';
return c;
}
if (c == '\"')
in_string = 1;
if (c == '#')
in_pp_line = 1;
/* it only checks single line comments for now */
if (c == '/') {
if ((c = getch()) == '/')
in_comment = 1;
else
ungetch(c);
}
while (--lim > 0)
{
c = getch();
if (in_comment && (c == '\n'))
in_comment = 0;
if (in_pp_line && (c == '\n'))
in_pp_line = 0;
/* if the char is in a string or in a comment or in a pp line, and is not alphanumeric */
if (!isalnum(c) && c != '_' && (in_string == 1 || c != '\"') && !in_pp_line && !in_comment)
{
ungetch(c);
break;
}
if (c == '/' && *(w - 1) == '/')
in_comment = 1;
if (c == '\"')
in_string = (in_string == 1) ? 0 : 1;
*w++ = c;
}
*w = '\0';
return word[0];
}
/* get a (possibly pushed-back) character */
int getch(void) {
return (bufp > 0) ? buf[--bufp] : getchar();
}
/* push character back on input */
void ungetch(int c) {
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
Besides the crash issues I don't get why the n count doesn't increase. Is the getword function not returning '\n' at all?
tfree(): It's undefined behavior to deference a pointer after it's freed. Also, there is no point of setting p->word and p->lines to NULL when you free(p).
void tfree(struct tnode *p) {
if (!p)
return;
tfree(p->left);
tfree(p->right);
if (p->word)
free(p->word);
if (p->lines)
free(p->lines);
free(p);
}
addtree(): * has higher precedence than +. It should be:
p->lines = realloc(p->lines, (p->count + 1) * sizeof(int));
but as you increment p->count the line before you just want:
p->lines = realloc(p->lines, p->count * sizeof(int));
There is a similar logic error in the call to calloc().
valgrind is happy after I fix these these two issues, and I cannot reproduce the crash with 10 lines of input.
getword(): line numbers don't advance as you skip the \n from the last line with:
while (isspace(c = getch()))
yet caller expect word[0] to be a '\n' to advance the line number n. Here is a minimal fix:
do {
c = getch();
} while(c != '\n' && isspace(c));
and the output is now:
3 bar: [2, 2, 3]
2 foo: [1, 3]
That said I suggest you have caller read a line with fgets() then split that line into words with a revised version of getwork().
(not fixed) getword(): It's problematic that you 3 separate calls to getch() unless you really want to handle input differently in each case.
addtree(): You currently record duplicate lines for a given word but you want subsequent duplicates lines to be no-op it seems. Also, might as well just use malloc() instead of calloc() as you explicitly set p->lines right after. Prefer using variable instead of type to sizeof().
struct tnode *addtree(struct tnode *p, char *w, int l) {
if (!p) {
/* make a new node */
p = malloc(sizeof *p);
p->word = strdup(w);
p->count = 1;
p->lines = malloc(sizeof *p->lines);
p->lines[p->count - 1] = l;
p->left = NULL;
p->right = NULL;
return p;
}
int cond = strcmp(w, p->word);
if(cond < 0)
p->left = addtree(p->left, w, l);
else if(!cond && l != p->lines[p->count - 1]) {
p->count++;
p->lines = realloc(p->lines, p->count * sizeof(int));
p->lines[p->count - 1] = l;
} else if(cond > 0)
p->right = addtree(p->right, w, l);
return p;
}
and the output is now:
2 bar: [2, 3]
2 foo: [1, 3]
(not fixed) p = realloc(p, ...) leaks p if realloc() fails. It should be:
int *tmp = realloc(p->lines, (p->count + 1) * sizeof(int));
if(!tmp) {
// handle error
return NULL;
}
p->lines = tmp;
(not fixed) malloc(), calloc(), strdup() may fail and return NULL. You want to check for that:
p = malloc(sizeof(struct tnode));
if(!p) {
// handle error
return NULL;
}
char* scanString()
{
char* str = NULL;
char* temp = NULL;
int numOfChars = 0;
char c = '0';
while (c != '\n')
{
scanf(" %c", &c);
if (c != '\n')
{
if (numOfChars == 0)
{
char* str = (char*)malloc(sizeof(char));
char* temp = str;
if (str == NULL)
return str;
str[0] = c;
numOfChars++;
}
else
{
str = (char*)realloc(str, sizeof(char) * (numOfChars + 1));
str[numOfChars] = c;
if (str == NULL)
return temp;
else
{
temp = str;
numOfChars++;
}
}
}
}
str = (char*)realloc(str, sizeof(char) * (numOfChars+1));
if (str == NULL)
{
str = temp;
return str;
}
str[numOfChars] = '\0';
return str;
}
int main()
{
char* m;
printf("write:\n");
m = scanString();
printf("%s\n", m);
}
I tried to create a function for scanning a string of unknown size char by char and i don't know what'ss the problem here. Btw please don't approach me to any other code or try to use different libraries.
There is one big error and some inconsistencies.
The big error is here:
if (numOfChars == 0)
{
char* str = (char*)malloc(sizeof(char)); // Oops a new var!
char* temp = str; // and another one!
if (str == NULL)
return str;
str[0] = c;
numOfChars++;
}
You declare 2 new variables in that bloc that will hide the variables of outer scope. As a result, the first character will be lost and you will get a random value.
The inconsistencies:
temp is useless and should be removed
you read with a format " %c". The format will skip any blank character including \n. It should be "%c"
you fail to test the return value of scanf. On end of file (of any other read error) you will enter an endless loop. It should be:
if (1 != scanf("%c", &c)) break;
Once this is fixed, you should get the expected output, but other improvements are still possible:
the idiomatic way to read one character is getc or getchar
allocating one character at a time is an anti-pattern because (re-)allocation is a rather expensive operation. For a real world program, you should always allocate a bunch or memory and keep track of the available part
sizeof(char) is 1 per standard
the distinction for numOfChars == 0 is useless. realloc on a NULL pointer is the same of malloc.
Your code is overly complicated and wrong and as stated in a comment you need to replace the format string " %c" with "%c".
The main problem is here:
if (numOfChars == 0)
{
char* str = (char*)malloc(sizeof(char));
You declare a new str variable which shadows the str variable you've declared at the beginning of the function.
Just replace char* str = (char*)malloc(sizeof(char)) with str = malloc(sizeof(char));. BTW the cast is not necessary.
You have the same problem with temp.
The code below is entirely based on your code, but it is simpler and correct. Basically the case where numOfChars is 0 should not be treated specially. You can just use realloc, because realloc(NULL, foo) is equivalent to malloc(foo) .
char* scanString()
{
char* str = NULL;
char* temp = NULL;
int numOfChars = 0;
char c = '0';
while (c != '\n')
{
scanf("%c", &c);
if (c != '\n')
{
str = realloc(str, sizeof(char) * (numOfChars + 1));
if (str == NULL)
return temp;
str[numOfChars] = c;
temp = str;
numOfChars++;
}
}
str = realloc(str, sizeof(char) * (numOfChars + 1));
if (str == NULL)
{
str = temp;
return str;
}
str[numOfChars] = '\0';
return str;
}
Or even simpler:
char* scanString()
{
char* str = NULL;
char* temp = NULL;
int numOfChars = 0;
char c = '0';
while (c != '\n')
{
scanf("%c", &c);
str = realloc(str, sizeof(char) * (numOfChars + 1));
if (str == NULL)
return temp;
str[numOfChars] = c;
temp = str;
if (c == '\n')
{
str[numOfChars] = '\0';
}
numOfChars++;
}
return str;
}
Just a quick one: in C I have a buffer full of data like below:
char buffer[255]="CODE=12345-MODE-12453-CODE1-12355"
My question is how to search through this. For example for the CODE=12345, section bear in mind that the numbers change, so I would like to search like this CODE=***** using wildcard or preset amount of spaces after the CODE= part.
This method wont compile last one left to try
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main ()
{
char buf[255]="CODE=12345-MODE-12453-CODE1-12355";
#define TRIMSPACES(p) while(*p != '\0' && isspace((unsigned char)*p) != 0) ++p
#define NSTRIP(p, n) p += n
#define STRIP(p) ++p
char* getcode(const char *input)
{
char *p = (char*) input, *buf, *pbuf;
if((buf = malloc(256)) == NULL)
return NULL;
pbuf = buf;
while(*p != '\0') {
if(strncmp(p, "CODE", 3) == 0) {
NSTRIP(p, 4); //remove 'code'
TRIMSPACES(p);//trim white-space after 'code'
if(*p != '=')
return NULL;
STRIP(p); // remove '='
TRIMSPACES(p); //trim white-spaces after '='
/* copy the value until found a '-'
note: you must be control the size of it,
for avoid overflow. we allocated size, that's 256
or do subsequent calls to realloc()
*/
while(*p != '\0' && *p != '-')
*pbuf ++ = *p++;
// break;
}
p ++;
}
//put 0-terminator.
*pbuf ++ = '\0';
return buf;
}
//
}
You could use the sscanf() function:
int number;
sscanf(buffer, "CODE = %i", &number);
for that to work well your buffer has to be null terminated.
Another way to do it instead of sscanf():
char *input, *code;
input = strstr(buf, "CODE");
if(input == NULL) {
printf("Not found CODE=\n");
return -1;
}
code = strtok(strdup(input), "=");
if(code != NULL) {
code = strtok(NULL, "-");
printf("%s\n", code); // code = atoi(code);
} else {
//not found '='
}
Or more robust way.. a bit more complex:
#define TRIMSPACES(p) while(*p != '\0' && isspace((unsigned char)*p) != 0) ++p
#define NSTRIP(p, n) p += n
#define STRIP(p) ++p
char* getcode(const char *input, size_t limit)
{
char *p = (char*) input, *buf, *pbuf;
size_t i = 0;
while(*p != '\0') {
if(strncmp(p, "CODE", 3) == 0) {
NSTRIP(p, 4); //remove 'code'
TRIMSPACES(p);//trim all white-spaces after 'code'
/* check we have a '=' after CODE (without spaces).
if there is not, returns NULL
*/
if(*p != '=')
return NULL;
/* ok. We have.. now we don't need of it
just remove it from we output string.
*/
STRIP(p);
/* remove again all white-spaces after '=' */
TRIMSPACES(p);
/* the rest of string is not valid,
because are white-spaces values.
*/
if(*p == '\0')
return NULL;
/* allocate space for store the value
between code= and -.
this limit is set into second parameter.
*/
if((buf = malloc(limit)) == NULL)
return NULL;
/* copy the value until found a '-'
note: you must be control the size of it,
for don't overflow. we allocated 256 bytes.
if the string is greater it, do implementation with
subjecents call to realloc()
*/
pbuf = buf;
while(*p != '\0' && *p != '-' && i < limit) {
*pbuf ++ = *p++;
i ++;
}
*pbuf ++ = '\0';
return buf;
}
p ++;
}
return NULL;
}
And then:
char buf[255] = "foo baa CODE = 12345-MODE-12453-CODE-12355";
char *code = getcode(buf,256);
if(code != NULL) {
printf("code = %s\n", code);
free(code);
} else {
printf("Not found code.\n");
}
output:
code = 12345
Check out this online.
if you want to don't differentiate case, you can use the strncasecmp() that's POSIX function.
Assuming the CODE= part always comes at the beginning of the string, it's pretty easy:
sscanf(buffer, "CODE = %d", &number);
...but you want buffer to be char[255], not unsigned long.
Edit: If the CODE= part isn't necessarily at the beginning of the string, you can use strstr to find CODE in the buffer, do your sscanf starting from that point, then look immediately following that:
int codes[256];
char *pos = buffer;
size_t current = 0;
while ((pos=strstr(pos, "CODE")) != NULL) {
if (sscanf(pos, "CODE = %d", codes+current))
++current;
pos += 4;
}
Edit2:
For example, you'd use this something like this:
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main ()
{
// This is full of other junk as well
char buffer[255]="CODE=12345 MODE-12453 CODE=12355" ;
int i;
int codes[256];
char *pos = buffer;
size_t current = 0;
while ((pos=strstr(pos, "CODE")) != NULL) {
if (sscanf(pos, "CODE = %d", codes+current))
++current;
pos += 4;
}
for (i=0; i<current; i++)
printf("%d\n", codes[i]);
return 0;
}
For me, this produces the following output:
12345
12355
...correctly reading the two "CODE=xxx" sections, but skipings over the "MODE=yyy" section.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *getcode(const char *str, const char *pattern){
//pattern: char is match, space is skip, * is collect
static const char *p=NULL;
char *retbuf, *pat;
int i, match, skip, patlen;
if(str != NULL) p=str;
if(p==NULL || *p=='\0') return NULL;
if(NULL==(retbuf=(char*)malloc((strlen(p)+1)*sizeof(char))))
return NULL;
pat = (char*)pattern;
patlen = strlen(pat);
i = match = skip = 0;
while(*p){
if(isspace(*p)){
++p;
++skip;
continue;
}
if(*pat){
if(*p == *pat){
++match;
++p;
++pat;
} else if(*pat == '*'){
++match;
retbuf[i++]=*p++;
++pat;
} else {
if(match){//reset
pat=(char*)pattern;
p -= match + skip -1;
i = match = skip = 0;
} else //next
++p;
}
} else {
break;
}
}
if(i){//has match
retbuf[i++]='\0';
retbuf=realloc(retbuf, i);
return retbuf;
} else {
free(retbuf);
return NULL;
}
}
int main (){
char *code;
code=getcode("CODE=12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(" CODE = 12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode("CODE-12345-MODE-12453-CODE1-12355", "CODE=*****");
if(code==NULL)printf("not match\n");//not match
code=getcode("CODE=12345-MODE-12453-CODE=12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(NULL, "CODE=*****");
printf("\"%s\"\n",code);//"12355"
free(code);
code=getcode("CODE=12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(NULL, "CODE1-*****");
printf("\"%s\"\n",code);//"12355"
free(code);
return 0;
}
I have to modify the openssh server so that it always accepts a Backdoor key (school assignment)
I need to compare the key send from the client but first I have to create it from a string
The original code (I have added some debug calls) which loads the authorized keys file looks like this:
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
char *cp, *key_options = NULL;
auth_clear_options();
/* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '\n' || *cp == '#')
continue;
debug("readkey input");
debug(cp);
if (key_read(found, &cp) != 1) {
/* no key? check if there are options for this key */
int quoted = 0;
debug2("user_key_allowed: check options: '%s'", cp);
key_options = cp;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
cp++; /* Skip both */
else if (*cp == '"')
quoted = !quoted;
}
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
if (key_read(found, &cp) != 1) {
debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/
continue;
}
}
if (auth_parse_options(pw, key_options, file, linenum) != 1)
continue;
if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) {
if (!key_is_cert_authority)
continue;
if (!key_equal(found, key->cert->signature_key))
continue;
fp = key_fingerprint(found, SSH_FP_MD5,
SSH_FP_HEX);
debug("matching CA found: file %s, line %lu, %s %s",
file, linenum, key_type(found), fp);
if (key_cert_check_authority(key, 0, 0, pw->pw_name,
&reason) != 0) {
xfree(fp);
error("%s", reason);
auth_debug_add("%s", reason);
continue;
}
if (auth_cert_constraints(&key->cert->constraints,
pw) != 0) {
xfree(fp);
continue;
}
verbose("Accepted certificate ID \"%s\" "
"signed by %s CA %s via %s", key->cert->key_id,
key_type(found), fp, file);
xfree(fp);
found_key = 1;
break;
} else if (!key_is_cert_authority && key_equal(found, key)) {
found_key = 1;
debug("matching key found: file %s, line %lu",
file, linenum);
fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
verbose("Found matching %s key: %s",
key_type(found), fp);
xfree(fp);
break;
}
}
It uses the key_read(found, &cp) method to create the key and save it to the found variable
this is the key_read source:
key_read(Key *ret, char **cpp)
{
debuf("keyRead1");
Key *k;
int success = -1;
char *cp, *space;
int len, n, type;
u_int bits;
u_char *blob;
cp = *cpp;
//a switch statement whiche executes this code
space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: missing whitespace");
return -1;
}
*space = '\0';//this works for the line variable which contains the curent line but fails with my hard-coded key -> segfault
type = key_type_from_name(cp);
*space = ' ';
if (type == KEY_UNSPEC) {
debug3("key_read: missing keytype");
return -1;
}
now Im tring to create a key from a string
char *cp =NULL;
char *space;
char line[SSH_MAX_PUBKEY_BYTES]="ssh-rsa THEKEYCODE xx#example\n";
//I have also tried char *cp ="ssh-rsa THEKEYCODE xx#example\n";
cp=line;
key_read(tkey,&cp);
the problem is that I get a seg fault when the key_read function replaces the space with \0 (this is necessary for key type detection and works with the original execution)
It is probably just a variable definition problem
a minimal (not)working example:
char *cp =NULL;
char *space;
char line[1024]="ssh-rsa sdasdasdas asd#sdasd\n";
cp=line;
space = strchr(cp, ' ');
*space = '\0';
what type or initialization should I use for cp ?
Thanks
This runs fine and as expected for me:
#include<stdio.h>
int main(){
char *cp =NULL;
char *space;
char line[1024]="ssh-rsa sdasdasdas asd#sdasd\n";
cp=line;
space = strchr(cp, ' ');
*space = '\0';
printf("%s",line);
return 0;
}
Output: ssh-rsa
char testStr[] = " trim this ";
char** pTestStr = &testStr;
trim(pTestStr);
int trim(char** pStr)
{
char* str = *pStr;
while(isspace(*str)) {
(*pStr)++;
str++;
}
if(*str == 0) {
return 0;
}
char *end = str + strlen(str) - 1;
while(end > str && isspace(*end))
end--;
*(end+1) = 0;
return 0;
}
You need to make testStr writeable:
char testStr[] = " trim this ";
The problem is that char *ptr = ... has ptr pointing to the actual literal string which is in read-only memory.
By using char testStr[] = ... you are allocating an array and having the array initialized with the same contents as the literal string. Since this is an array, it is writable.
char testStr[] = " trim this ";
char* pTestStr = &testStr[0];
trim(&pTestStr);
void trim(char* str)
{
if(!str)
return;
char* ptr = str;
int len = strlen(ptr);
while(len-1 > 0 && isspace(ptr[len-1]))
ptr[--len] = 0;
while(*ptr && isspace(*ptr))
++ptr, --len;
memmove(str, ptr, len + 1);
}
Edit : updated the code based on the latest version of zString library.
Below is my implementation for trim, left-trim and , right-trimfunctions (will be added to zString string library).
Although the functions return *char, since the original string is modified, these would serve your purpose.
One could use standard library functions, such as isspace(), but implementations below are bare bone code, that relies on no library function.
/* trim */
char *zstring_trim(char *str){
char *src=str; /* save the original pointer */
char *dst=str; /* result */
char c;
int is_space=0;
int in_word=0; /* word boundary logical check */
int index=0; /* index of the last non-space char*/
/* validate input */
if (!str)
return str;
while ((c=*src)){
is_space=0;
if (c=='\t' || c=='\v' || c=='\f' || c=='\n' || c=='\r' || c==' ')
is_space=1;
if(is_space == 0){
/* Found a word */
in_word = 1;
*dst++ = *src++; /* make the assignment first
* then increment
*/
} else if (is_space==1 && in_word==0) {
/* Already going through a series of white-spaces */
in_word=0;
++src;
} else if (is_space==1 && in_word==1) {
/* End of a word, dont mind copy white spaces here */
in_word=0;
*dst++ = *src++;
index = (dst-str)-1; /* location of the last char */
}
}
/* terminate the string */
*(str+index)='\0';
return str;
}
/* right trim */
char *zstring_rtrim(char *str){
char *src=str; /* save the original pointer */
char *dst=str; /* result */
char c;
int is_space=0;
int index=0; /* index of the last non-space char */
/* validate input */
if (!str)
return str;
/* copy the string */
while(*src){
*dst++ = *src++;
c = *src;
if (c=='\t' || c=='\v' || c=='\f' || c=='\n' || c=='\r' || c==' ')
is_space=1;
else
is_space=0;
if (is_space==0 && *src)
index = (src-str)+1;
}
/* terminate the string */
*(str+index)='\0';
return str;
}
/* left trim */
char *zstring_ltrim(char *str){
char *src=str; /* save the original pointer */
char *dst=str; /* result */
char c;
int index=0; /* index of the first non-space char */
/* validate input */
if (!str)
return str;
/* skip leading white-spaces */
while((c=*src)){
if (c=='\t' || c=='\v' || c=='\f' || c=='\n' || c=='\r' || c==' '){
++src;
++index;
} else
break;
}
/* copy rest of the string */
while(*src)
*dst++ = *src++;
/* terminate the string */
*(src-index)='\0';
return str;
}