i got a new task from my teach to implement some basic string operations like append, remove, substr and insert.
while i was thinking at how should i approach this problem i thought i could just write a function which does the copying and ...
int copy(char* buffer,char * string,int begin,int end)
{
if(end == 0)
end = length(string);
//Copy from begin to end and save result into buffer
for(int i = 0; i < end;i++)
buffer[i] = *(string+begin+i);
return end;
}
with that implementation, so my idea i could just implement all the other functions asked by my teacher like this :
void insert(char* buffer,char * string, char * toInsert, int begin,int end)
{
//Copy till the position of the original string
begin = copy(buffer,
string,0,begin);
//Insert
//copy from the last change of the original string
begin = copy(buffer+begin,
toInsert,0,end);
//Copy whats left
copy(buffer+begin,
string);
}
So if i now try to insert something with this function i get some weird output:
int main() {
char * Hallo = "Hello World how are things?";
char * appendix = "Halt die schnauze!";
char buffer[128];
for (int i = 0; i < 128;i++)
buffer[i] = -0;
insert(buffer,Hallo,appendix,5,0);
printf("%s\n",buffer);
return 0;
}
output: HelloHalt die schnHello World how are things?
I simply cannot get my head around why the output does look like this. Do i have a logical mistake there?
fix like this:
#include <stdio.h>
size_t length(const char *s){
size_t len = 0;
while(*s++){
++len;
}
return len;
}
int copy(char *buffer, const char *string, int begin, int end){
int len = 0;//copy length
if(end == 0)
end = length(string);
for(int i = begin; i < end; i++)//End position is not included
buffer[len++] = string[i];
return len;
}
void insert(char *buffer, const char *string, const char *toInsert, int begin, int end){
int len;
len = copy(buffer, string, 0, begin);
len += copy(buffer + len, toInsert, 0, end);
len += copy(buffer + len, string, begin, end);
buffer[len] = 0;
}
int main(void) {
char * Hallo = "Hello World how are things?";
char * appendix = "Halt die schnauze!";
char buffer[128] = {0};
insert(buffer, Hallo, appendix, 5, 0);
printf("%s\n",buffer);
return 0;
}
Related
I have been trying to convert a string in array of integers, floats and characters. While I could get it work for integers and floats, there is some problem for characters.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s1;
int k, no=5;
char* variable = "R1,R2,R3,R4,R5";
void* value;
s1 = calloc(no,sizeof(char)*81);
for (k=0; k<no; k++) s1[k] = strdup(mchar);
ListChar(variable, s1, no, ",");
memcpy(value, s1, no*sizeof(char)*81);
free(s1);
int i;
for (i = 0; i < no; i++)
printf("%s", value[i]);
printf("\n");
return 0;
}
In the header file I have
#define mchar "A...(81times)"
Implementation:
int ListChar(char *buf, char *list, int maxloop, char* delim)
{
int n = 0;
char *s,*t;
s= strdup(buf);
t= strtok(s,delim);
while ( t && (n<maxloop))
{
if (list!=NULL) list[n] =strdup(t);
n++;
t=strtok(NULL,delim);
}
free(s);
return(n);
}
During the calloc memory assignment when I watch s1 its 0xsomeadress ""
After the for loop s1 becomes 0xsomeadress "Garbage value 81 times"
When s1 is assigned to list its still reads the same garbage value.
And when list [n] = strdup(t) list[0] reads the first block of garbage value like -21 '\221 ṗ'.
t is getting delimited correctly. I even tried initializing char *s1[81] = {"something"} and looping it on j but it wont work, same problem, and I need to free s1 at the end because this function runs for number of times. I did it for integers and floats by list[n]=atoi(t) it works fine. Can anyone suggest me something?
There seems to be a fundamental misunderstanding about how strings work. Your s1 clearly needs to be a char ** and the usage of strdup is incorrect. If s1 is of type char *, then s1[k] is of type char. But strdup returns a char *, so s1[k] = strdup ... is clearly an error which your compiler ought to warn you about. Perhaps you want something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void * xmalloc(size_t s);
void
ListChar(const char *buf, char **list, int maxloop, int delim)
{
char set[] = {delim, 0};
for( int n = 0; n < maxloop; n += 1 ){
size_t len = strcspn(buf, set);
list[n] = xmalloc(len + 1);
memcpy(list[n], buf, len);
buf += len + 1;
}
}
int
main(int argc, char **argv)
{
int delim = ',';
(void)argc; /* Suppress compiler warning */
while( *++argv ){
char **s1;
int k, num = 1;
char *input = *argv;
for( const char *p = input; *p; p += 1 ){
if( *p == delim ){
num += 1;
}
}
s1 = xmalloc(num * sizeof *s1);
ListChar(input, s1, num, delim);
for( int i = 0; i < num; i += 1 ){
printf("%s\n", s1[i]);
}
free(s1);
}
return 0;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}
Note that the above code scans each string twice, which is not ideal. Rather than scanning the string to find the number of delimiters and then parsing the string, it would be better to do both in one pass. But for the purposes of demonstrating how to break up the string, that seems like unnecessary complexity. (Though it's actually simpler, IMO)
I have this simple function for extrapolate a substring in a string.
char* substr(const char *string, size_t start, size_t end) {
const char *char_start = &string[start];
const char *char_end = &string[end];
char *substring = (char *) calloc(1, char_end - char_start + 1);
memcpy(substring, char_start, char_end - char_start + 1);
return substring;
}
I have only one calloc, that create the returned string.
I try the code in a cycle, for extrapolate the substring of a string array.
This is the main code where I test the function:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t i;
char *tmp = NULL;
char *kmer_array[5] = {"GTGAA", "ACGGT", "AACGG", "AGTGA", "TGAAC"};
for ( i = 0; i < 5; i++ ) {
tmp = substr(kmer_array[i], 1, strlen(kmer_array[i]));
}
free(tmp);
return 0;
}
But when I test the code with valgrind this is the output (link).
I dont't understade where I lost the byte
You set tmp inside the loop 5 times but only free the last one (outside the loop)
I have two string shown below:
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
In a part of the program I used the following code where it increments the pointers for both strings to point to the next characters.
ch_A = text_to_compare[i++];
ch_B = dictionary[j++];
Why is pointer j being incremented but pointer i is remaining as it was?
Thanks in advance.
EDIT: Below is the full code. The aim of this project is to compare a string with a list of words. Integer i is not incrementing only after the program enters the else statement.
#include <string.h>
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
int bring_characters(char pdata *, char pdata *, char ch_A, char ch_B, char i,
char j);
void main(void) {
unsigned char ch_A;
unsigned char ch_B;
unsigned char i = 0;
unsigned char j = 0;
char pdata N1;
char pdata N2;
int result;
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j];
result = bring_characters(&N1, &N2, ch_A, ch_B, i, j);
if (result == 0) {
while (1)
;
}
else {
while (1)
;
}
while (1)
;
}
int bring_characters(char pdata *N1, char pdata *N2, char ch_A, char ch_B,
char i, char j) {
do {
if (ch_A == ch_B) {
ch_A = text_to_compare[i++]; // take a caharacter from the text
ch_B = dictionary[j++];
if ((ch_A == '\0') && ((ch_B == ',') || (ch_B == '.'))) {
while (1)
; // load idata-------------------------------------------------------------------------------------------------
}
}
else {
i = 0; // refresh pointer
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j++];
}
} while (ch_B != '.');
return (0);
}
Whew, there's a lot going on here! Now that you've added the full code it looks like in your attempt to move on to the next word you have prevented yourself from moving on.. you'll need to do some major revisions to get this guy working.
The first thing you need to do is figure out how you would do this on paper, then step by step try to reproduce that in your code.
Here's a function to kickstart you:
int find_next_match(char toFind, int startingPosition, char* mainString){
int counter = startingPosition;
char buf = mainString[counter];
while(buf != NULL){
if (buf == toFind){
return counter;
}
counter++;
buf = mainString[counter];
}
return -1; //error
}
You can use something like this to find the next instance of the first character in your string, then you can implement a loop to determine if that is a match.
Good luck, you can do it!
i got a problem with my C code.
int split(char* source, char*** target, char* splitChar) {
int i;
int currentLength;
int splitCharPosition;
char* currentSubstring = source;
int splitCount = charcount(source, splitChar) + 1;
*target = (char**) malloc(splitCount * sizeof(char**));
for(i=0;i<splitCount;i++) {
splitCharPosition = indexOf(currentSubstring, splitChar);
substring(currentSubstring, target[i], 0, splitCharPosition);
currentLength = strlen(currentSubstring);
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
}
return splitCount;
}
The problem is that if I use the Debugger, the pointer to splitChar is set to 0x0 after the first run of the for loop.
Does anybody know why it is set to 0x0?
EDIT:
int indexOf(char* source, char* template) {
int i;
int j;
int index;
for (i = 0; source[i]; i++) {
index = i;
for (j = 0; template[j]; j++) {
if (source[i + j] != template[j]) {
index = -1;
break;
}
}
if (index != -1) {
return index;
}
}
return -1;
}
EDIT2:
int charcount(char* source, const char* countChar) {
int i;
int count = 0;
for(i=0;source[i];i++) {
if(source[i] == countChar[0]) {
count++;
}
}
return count;
}
EDIT3:
char* substring(char* source, char** target, int start, int length) {
*target = (char*) malloc(length + 1);
strncpy(*target, source + start, length);
target[length] = '\0';
return *target;
}
EDIT4:
I just noticed that if I add
char* sndfpgjps = splitChar;
to my split() code it does not delete the reference. Anyone know why?
This line:-
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
... will cause a memory leak, as well as being incredibly inefficient. The old substring is left dangling. and never freed.
It would be much better to write
currentSubString += splitCharPosition + 1;
I don't think that's the problem, but it's a problem.
Also, as you're using C library functions like strlen(), why aren't you using strtok or better yet, strtok_r?
I have some reservations about the code, but this works cleanly under valgrind (no leaks, no abuse). I've left the sub-functions largely unchanged except that constant strings are marked constant. The code in split() has been simplified. As I noted in a comment, I suggest writing the main split() function so that you have a local char **string_list; which you allocate and fill. Then, when you're about to return, you assign *target = string_list;. This will make it easier for you to understand what's going on. Triple indirection is nasty. You can justify it here (just), but minimize the time you spend working with triple pointers. The revision adopts that strategy.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
Note that in the second example, charcount() returns 6 but there are only 4 strings. This caused a late adjustment to the source code. (You could realloc() the result so it is exactly the right size, but it probably isn't worth worrying about unless the discrepancy is really marked — say 'more than 10 entries'.) The error handling is not perfect; it doesn't access invalid memory after failure to allocate, but it doesn't stop trying to allocate, either. Nor does it report failures to allocate individual strings — it does for failure to allocate the array of pointers.
I'd probably avoid the triple pointer by creating a structure:
typedef struct StringList
{
size_t nstrings;
char **strings;
} StringList;
You can then pass a pointer to one of these into split(), and into the utility functions such as free_list() and print_list(). The free_list() function would then modify the structure so that both elements are zeroed after the data pointed at by the structure is freed.
I'd also be tempted to use a different implementation of indexOf():
int indexOf(const char *haystack, const char *needle)
{
const char *pos = strstr(haystack, needle);
if (pos != 0)
return (pos - haystack);
return -1;
}
I do not know what substring does, nor what signature it has, but in the line
substring(currentSubstring, target[i], 0, splitCharPosition);
target[i] is only defined for i==0. I believe you wanted to write
substring(currentSubstring, (*target)[i], 0, splitCharPosition);
See if your debugger also supports data breakpoints, i.e. break if some place in memory is modified. Then place one at the actual address of splitChar, and another at the address it points to. (Since you didn't specify whether the pointer is null or points to nil.) See where it breaks. It may be that it is a completely unrelated place; that would indicate a buffer overflow.
Also, you could make at least splitChar a pointer to const. You don't actually want to modify it, right? Better idea, make it a char, not a pointer, since its name suggests that there is only one character on which you split, not a string.
The first call to substring does not look correct:
substring(currentSubstring, target[i], 0, splitCharPosition);
I suspect it should be something like the following where it indexes the actual memory that was allocated:
substring(currentSubstring, &((*target)[i]), 0, splitCharPosition);
You first need to get the value that target points at (*target) and then index off of that and pass the address of that array location.
I wrote a functions to parse a NMEA sentence, store parameters in separate arrays and write their values.
First I ran it in console and everything worked as expected. The functions along the test commands in main() are the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06
char *get_substring(size_t start, size_t stop, const char *src, char *dst, size_t size)
{
int count = stop - start;
if ( count >= --size )
{
count = size;
}
sprintf(dst, "%.*s", count, src + start);
return dst;
}
void get_separator_position(char *input_string, int *separators_array, int separators_count)
{
//10 separators
char *separator = ",";
char *current_string = input_string;
int current = 0;
char *found;
int pos;
int cur_pos = 0;
for(current = 0; current < separators_count; current++)
{
found = strstr(current_string, separator);
if(found != NULL)
{
pos = found - current_string;
cur_pos += pos;
separators_array[current] = cur_pos + current;
current_string = &input_string[cur_pos + 1 + current];
}
else
{
//printf("Not found!\n");
}
}
}
void parse_nmea_string(char *nmea_string, char *utc, char *latitude, char *longitude, char *hdop, char *altitude, char *fix, char *cog, char *spkm, char *spkn, char *date, char *nsat)
{
//10 separators "," in NMEA sentence
int separators_array[10];
get_separator_position(nmea_string, &separators_array[0], 10);
int length = strlen(nmea_string);
utc = get_substring(9, separators_array[0] + 1, nmea_string, utc, sizeof(char) * (separators_array[0] - 9 + 1));
latitude = get_substring(separators_array[0] + 1, separators_array[1], nmea_string, latitude, sizeof(char) * (separators_array[1] - separators_array[0]));
longitude = get_substring(separators_array[1] + 1, separators_array[2], nmea_string, longitude, sizeof(char) * (separators_array[2] - separators_array[1]));
hdop = get_substring(separators_array[2] + 1, separators_array[3], nmea_string, hdop, sizeof(char) * (separators_array[3] - separators_array[2]));
altitude = get_substring(separators_array[3] + 1, separators_array[4], nmea_string, altitude, sizeof(char) * (separators_array[4] - separators_array[3]));
fix = get_substring(separators_array[4] + 1, separators_array[5], nmea_string, fix, sizeof(char) * (separators_array[5] - separators_array[4]));
cog = get_substring(separators_array[5] + 1, separators_array[6], nmea_string, cog, sizeof(char) * (separators_array[6] - separators_array[5]));
spkm = get_substring(separators_array[6] + 1, separators_array[7], nmea_string, spkm, sizeof(char) * (separators_array[7] - separators_array[6]));
spkn = get_substring(separators_array[7] + 1, separators_array[8], nmea_string, spkn, sizeof(char) * (separators_array[8] - separators_array[7]));
date = get_substring(separators_array[8] + 1, separators_array[9], nmea_string, date, sizeof(char) * (separators_array[9] - separators_array[8]));
nsat = get_substring(separators_array[9] + 1, length, nmea_string, nsat, sizeof(char) * (length - separators_array[9]));
}
int main(int argc, char *argv[])
{
static const char text[] = "$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06";
char utc[20];
char latitude[30];
char longitude[20];
char hdop[20];
char altitude[20];
char fix[20];
char cog[20];
char spkm[20];
char spkn[20];
char date[20];
char nsat[20];
printf("Separator %d at position %d\n", pos, separators_array[pos]);
parse_nmea_string(text, utc, latitude, longitude, hdop, altitude, fix, cog, spkm, spkn, date, nsat);
printf("UTC: %s\n", utc);
system("PAUSE");
return 0;
}
This code works fine and the test output is
UTC: 200949.000
Then I tried to use the above function on the microcontroller project and write the array values using the existing debug_str() function which is the following:
// Debug function prints string msg to UART1 (to PC)
void debug_str(const char* msg)
{
#ifdef debug
putchar1(0x24); //$
while(*msg)
{
putchar1(*msg++);
}
putchar1(0x0D); //Carriage Return
#endif
}
So combining the parsing functions with existing code I tried to write the array values the following way:
char UTC[15];
char latitude[15];
char longitude[15];
char hdop[6];
char altitude[9];
char fix[5];
char cog[10];
char spkm[8];
char spkn[8];
char date[10];
char nsat[6];
static const char nmea_test[] = "$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06";
...
parse_nmea_string(nmea_test, UTC, latitude, longitude, hdop, altitude, fix, cog, spkm, spkn, date, nsat);
debug_str(latitude);
But this way the output was not correct.
Output:
$*s
Does anyone what the problem is and how to correctly store and write to the output the parameters which are parsed from the string nmea_test?
Thank you!
You should understand the difference between arrays and pointers in C.
Read any good C textbook about this.
Your get_substring function don't do what you expect. It does not allocate any string for its result.
You might consider using strdup inside get_substring, and adopt the convention that the caller should free the result.
Now it works. Functions get_substring and get_separator_positions had to be modified the following way:
char *get_substring(unsigned int start, unsigned int stop, const char *src, char *dst, unsigned int size)
{
int count = stop - start;
if ( count >= --size )
{
count = size;
}
// sprintf(dst, "%.*s", count, src + start); - this line was replaced by the following two lines (the microcontroller does not support strdup so strncpy had to be used)
strncpy(dst, &src[start], size);
dst[size] = '\n';
return dst;
}
//char input_string[] = "$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06";
void get_separator_position(char *input_string, int *separators_array, int separators_count)
{
//10 separators
char separator[] = ",";//char *separator = "," didn't work
char *current_string = input_string;
int current = 0;
char *found;
int pos;
int cur_pos = 0;
//char tmp_pos[10];
for(current = 0; current < separators_count; current++)
{
found = strstr(current_string, separator);
if(found != NULL)
{
debug_str("found!");
//debug_str(found);
pos = found - current_string;
// itoa(pos,tmp_pos);
// debug_str(tmp_pos);
cur_pos += pos;
separators_array[current] = cur_pos + current;
current_string = &input_string[cur_pos + 1 + current];
}
else
{
debug_str("Not found!");
}
}
}