Please have a look at the following code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
const char * cmd;
const char * help;
} CmdEnum;
static CmdEnum cmd_enum[] = {
{"help", "This help..."},
{"first", "The first command"},
{"second", "The second command"},
};
void main()
{
int i,n;
char *out = "";
n = sizeof(cmd_enum) / sizeof(CmdEnum);
for (i=0; i<n; i++)
{
char *oldOut = out;
CmdEnum cmd = cmd_enum[i];
asprintf(&out, "%s%s -> %s\n", oldOut, cmd.cmd, cmd.help);
if(i>0) free(oldOut);
}
printf("%s", out);
printf("Done.\n");
}
Is this a good way to build a text from the CmdEnum?
Is there a "nicer" way do define cmd in the first place as to avoid the if(i>0) free...?
Or am I doing something entirely wrong?
EDIT:
After reading larsmans' answer I modified main to:
int main()
{
int i,n, copied, siz;
char *out, *cursor;
siz = 1;// 1 for NUL char
n = sizeof(cmd_enum) / sizeof(CmdEnum);
for (i=0; i<n; i++)
{
siz += strlen(cmd_enum[i].cmd) + strlen(cmd_enum[i].help) + strlen(":\n\t\n\n");
}
out = malloc(siz);
if(!out)
{
printf("Could not alloc!\n");
return 1;
}
cursor = out;
for (i=0; i<n; i++)
{
copied = snprintf(cursor, siz, "%s:\n\t%s\n\n", cmd_enum[i].cmd, cmd_enum[i].help);
if(copied < 0 || copied >= siz)
{
printf("snprintf failed: %i chars copied.\n", copied);
return 1;
}
cursor += copied;
siz -= copied;
}
printf("%s", out);
printf("Done.\n");
free(out);
return 0;
}
(Note: I also changed the output format...)
Is this a good way to build a text from the CmdEnum?
Yes, except that asprintf is not portable (although you can define it easily in terms of snprintf for platforms that don't have it) and you're not checking error returns. void main isn't valid C btw.
Is there a "nicer" way do define cmd in the first place as to avoid the if(i>0) free...?
You could allocate the whole string beforehand.
size_t i, siz = 1; // 1 for NUL char
for (i=0; i<n; i++)
siz += strlen(cmd_enum[i].cmd) + strlen(cmd_enum[i].help) + strlen(" -> \n");
char *out = malloc(siz);
// check for errors
then build the string with snprintf. This saves you some malloc'ing and error checking in the loop.
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 wrote a program to split given string according to certain delimiter. Everything works fine but there are leak and error in valgrind.
split algorithm is correct.
substr works fine.
My program:
#include <stdio.h>
#include <stdlib.h>
char** split(const char*, char, int*);
char* substr(const char*, int, int);
void freepath(char**, int);
int main(void) {
char *str = "home///ubuntu//Desktop";
char **path = NULL;
int size = 0;
path = split(str, '/', &size);
freepath(path, size);
return 0;
}
char** split(const char *str, char c, int *size) {
char **path = NULL;
const char *save = str;
int from=-1, i;
if(str == NULL)
return NULL;
for(i=0 ; 1; ++i) {
if(*str == '\0') {
if(from != -1) {
++(*size);
path = (char**)realloc(path, (sizeof(char**) *(*size)));
*(path+(*size)-1) = substr(save, from, i);
}
break;
}
if(*str != '/') {
if(from == -1)
from = i;
}
else {
if(from != -1) {
++(*size);
path = (char**)realloc(path, (sizeof(char)*(*size)));
*(path+(*size)-1) = substr(save, from, i);
}
from = -1;
}
++str;
}
return path;
}
void freepath(char **path, int size) {
int i=0;
for(i=0; i<size; ++i) {
free(*(path+i));
*(path+i) = NULL;
}
free(path);
path = NULL;
}
char* substr(const char *src, int m, int n)
{
int len = n - m;
char *dest = (char*)malloc(sizeof(char) * (len + 1));
for (int i = m; i < n && (*(src + i) != '\0'); i++)
{
*dest = *(src + i);
++dest;
}
*dest = '\0';
return dest - len;
}
Valgrind output:
What should be the reason ? , I really stuck with it !
clang analyser has found 4 suspected points in your code:
1.
char *str = "home///ubuntu//Desktop";
needs const in front of char (pointer to const).
2.
char** split(const char *str, char c, int *size) {
contains an unused parameter (c).
3.
path = (char**)realloc(path, (sizeof(char**) *(*size)));
clang-analyser does not like char** as the argument of sizeof, replacing it with char* removes the warning.
4.
path = (char**)realloc(path, (sizeof(char)*(*size)));
The same warning as in 3. Errr, no, not the same. Bingo! Replace char inside sizeof with char* and you're back home.
One final remark. When you use valgrind, always add debugging information to the compiled code, that is, add -g to the compiler command-line options (gcc, clang, etc.). This will give you the information about the exact lines numbers in your source code corresponding to the places where the problem was spotted by valgrind. My screenshot of your program under valgrind contains more information than yours:
Please notice that valgrind correctly identifies line 44 as the line with the buggy memory allocation (or line 45 with a buggy usage of the buffer allocated at line 44. Both options are a priori possibly correct).
struct string {
size_t length;
size_t allocated;
char* data;
};
string* strCreate(char* str) {...}
string* strSubstring(string* str, size_t pos, size_t len) {...}
char* strGet(string* str) {
return str->data;
}
size_t findFrist(string* str, char what, size_t pos) {
for(size_t i = pos; i < str->length; ++i) {
if(str->data[i] == what)
return i;
}
return -1;
}
string** strTokenizer(string* str) {
string** res;
res = malloc(sizeof(char*)*90); //*90 (token num)
for(int i=0; i<90; i++) //i<90 (token num)
res[i] = malloc(sizeof(char)*100); //*100 (a token lenght)
size_t first = 0;
size_t i = 0;
while(first < str->length) {
int second = findFrist(str,' ',first);
if(second == - 1)
second = str->length;
string* token = strSubstring(str,first, second - first);
if(*strGet(token) != ' ')
res[i] = token;
first = second + 1;
++i;
}
return res;
}
int main() {
string* fe = strCreate("A string \ tof");
string** r = strTokenizer(fe);
for(int i = 0; i < 4; ++i) {
printf("%s",strGet(r[i]));
}
return 0;
}
I want to create a string tokenizer. When I want to print the string in the main function it not print the \. The other thing is that how to allocate string** res in proper way. When I allocate for the sizeof(char*) the only way that I see is loop through the string, but I was just wondering is this possible to allocate without going through the string 2 times in the tokenizer function.
I do not want to use strtok
typedef struct string string in the .h file
When compiling the code using GCC 10.2.0 with options:
gcc -O3 -g -std=c11 -Wall -Wextra -Werror …
I get the message:
bs83.c:85:44: error: unknown escape sequence: '\040' [-Werror]
85 | string *fe = strCreate("A string \ tof");
As I noted in the comments, the string "A string \ tof" is malformed — your compiler should be warning you about it. If you want a backslash in a string, you write (for example), "A string \\ tof". Backslash-space has no defined meaning; it is probably being interpreted as a single space. Maybe you should print the argument to strCreate() to validate this.
You also need typedef struct string string; near the top of the code for it to compile with a C compiler (and the headers).
Here is a fixed version of your code — because of the compilation options I use, the functions need to be either static or declared before being defined; I make them static since the only reason to make them non-static (IMO) is if they're accessed from another source file, and then they'd be declared in a header. That probably applies to your code — there is mention of a header.
Here's fixed code that works:
/* SO 6537-9584 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct string string;
struct string
{
size_t length;
size_t allocated;
char *data;
};
static
string *strCreate(char *str)
{
string *s = malloc(sizeof(string));
s->length = strlen(str);
s->allocated = s->length * 2;
s->data = (char *)malloc(s->allocated + 1);
memcpy(s->data, str, s->length);
s->data[s->length] = '\0';
return s;
}
static
string *strSubstring(string *str, size_t pos, size_t len)
{
string *s = malloc(sizeof(string));
s->length = len;
s->allocated = s->length * 2;
s->data = (char *)malloc(s->allocated + 1);
memcpy(s->data, &str->data[pos], s->length);
s->data[s->length] = '\0';
return s;
}
static
char *strGet(string *str)
{
return str->data;
}
static
size_t findFirst(string *str, char what, size_t pos)
{
for (size_t i = pos; i < str->length; ++i)
{
if (str->data[i] == what)
return i;
}
return -1;
}
static
string **strTokenizer(string *str)
{
string **res;
res = malloc(sizeof(char *) * 90); // *90 (token num)
for (int i = 0; i < 90; i++) // i<90 (token num)
res[i] = malloc(sizeof(char) * 100); // *100 (a token length)
size_t first = 0;
size_t i = 0;
while (first < str->length)
{
int second = findFirst(str, ' ', first);
if (second == -1)
second = str->length;
string *token = strSubstring(str, first, second - first);
if (*strGet(token) != ' ')
res[i] = token;
first = second + 1;
++i;
}
return res;
}
int main(void)
{
string *fe = strCreate("A string \\ tof");
string **r = strTokenizer(fe);
for (int i = 0; i < 4; ++i)
{
printf("[[%s]]\n", strGet(r[i]));
}
return 0;
}
The output is:
[[A]]
[[string]]
[[\]]
[[tof]]
Note the use of [[ and ]] around the printed strings (and the newlines). It makes it easier to identify trailing blanks and embedded carriage return characters and various other mishaps.
My program compiles but I am not working with pointers and realloc correctly. I have tried looking at other examples but I can't seem to translate it to my own program. The point of the program is to read in words from a file and increment the count if they appear more than once. Once the array of structs goes over my base (5), I want to realloc space, copy the array over and then add the next word.
Any help would be greatly appreciated!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BASE 5
#define MAX 50
typedef char *string;
struct wordCount
{
string word;
unsigned int count;
};
int main (void)
{
unsigned int i;
unsigned int incremented;
unsigned int j;
char temp [40];
struct wordCount wordArray[BASE];
struct wordCount *holder;
FILE *infile;
j = 0;
infile = fopen("input.txt","r");
while (fscanf(infile, "%s", temp) == 1) {
incremented = 0;
for (i = 0; i < j; i++){
if(strcmp(temp,wordArray[i].word) == 0){
wordArray[i].count++;
incremented++;
}
}
if (incremented == 0){
if (j<BASE){
wordArray[j].word = (char *)malloc((strlen(temp)+1) *
sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
} else {
holder = realloc(wordArray, sizeof(wordArray) +1);
*wordArray = *holder;
wordArray[j].word = (char *)malloc((strlen(temp)+1) * sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
}
}
}
fclose(infile);
/* bring in next file*/
/*delete du plicates */
/*sort*/
for (i = 0; i < j; i++) {
printf("%s ", wordArray[i].word);
printf("%d\n", wordArray[i].count);
}
/* and when done:*/
for(i = 0; i < j; i++){
free(wordArray[i].word);
}
return 0;
}
Here's the most obvious place you're going wrong:
holder = realloc(wordArray, sizeof(wordArray) +1);
Note this line from the man page of realloc():
void *realloc(void *ptr, size_t size);
...
Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc().
Your wordArray is a statically allocated array, it was not dynamically allocated via malloc() or friends.
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.