I'm reading bytes from a socket and copying it into a char array.
char usrInputStr[256];
if ((rbytes = read(STDIN_FILENO, usrInputStr, 256)) < 0) {
perror("Read error: ");
exit(-1);
}
char finalStr[rbytes + 1];
memcpy(finalStr, usrInputStr, rbytes);
Now I allot an array on the heap and split the string into words and put each word in an array of char arrays. This is the code that does that.
char** currentTokens = (char**)malloc(sizeof(char*) * 256);
for(int i = 0; i < 256; i++) {
currentTokens[i] = (char*)malloc(sizeof(char) * 256);
}
int sz = splitStrToArray(finalStr, currentTokens);
The definition of the splitStrToArray function is here,this works fine.
int splitStrToArray(char* str, char** arr) {
int count = 0;
char* buffer;
int len = strlen(str);
for (int i = 0; i < len ; ++i) {
if(isspace(str[i])) {
count++;
}
}
int index = 0;
buffer = strtok(str, " ");
while(buffer != NULL) {
memcpy(arr[index], buffer, strlen(buffer));
index++;
buffer = strtok(NULL, " ");
}
return count;
}
However when I compare this with user input it doest return zero and thus the two string don't match.
if(strncasecmp(currentTokens[0], "quit") == 0) {
printf("quit" );
breakTrigger = 1;
} else if(strcasecmp(currentTokens[0], "q") == 0) {
printf("q");
breakTrigger = 1;
} else {
callback(currentTokens, sz, port);
}
I've checked currentTokens[0] and the word is correct.
When the I try to take the return value of strcasecmp in an int and print it I get Segmentation Fault.
I'm new to C, any help appreciated.
None of your strings are null-terminated so you have undefined behaviour throughout. Using memcpy to copy strings is almost never what you want.
You should consider using strdup, if available. Otherwise malloc and then strcpy.
In the particular case of finalStr, I see no good reason to perform the copy at all. Just read directly into it (and don't forget to null-terminate.) Alternatively, use the standard C library instead of the underlying posix layer.
Related
So I have been searching through stack overflow for a little over an hour and I don't understand why this function is giving me a segmentation error. I want to create a string array, scan strings in through scanf, dynamically change the size of each string and return the string array. Can anyone help? Thank you.
char** readScores(int* count) {
int c = 0;
char** arr =(char**)malloc(100 * sizeof(char*));
char* in;
while(scanf("%s", in) != EOF) {
arr[c] = (char*)malloc(strlen(in)+1);
strcpy(arr[c], in);
}
*count = c;
return arr;
}
char* in;
while(scanf("%s", in) != EOF) {
This tells the computer to read from standard input into the char buffer that in points to.
Which does not exist, because in is not initialised to anything (let alone a valid buffer).
I would not use scanf only fgets.
You need to allocate memory dor the arr and for every line referenced by elements of arr
char** readScores(size_t *count) {
size_t lines = 0;
char** arr = NULL, **tmp;
char* in = malloc(MAXLINE), *result;
size_t len;
if(in)
{
do{
result = fgets(in, MAXLINE, stdin);
if(result)
{
len = strlen(in);
tmp = realloc(arr, sizeof(*tmp) * (lines + 1));
if(tmp)
{
arr = tmp;
len = strlen(in);
arr[lines] = malloc(len + (len == 0));
if(arr[lines])
{
if(len) memcpy(arr[lines], in, len - 1);
arr[lines++][len] = 0;
}
else
{
// error handling
}
}
else
{
// error handling
}
}
}while(result);
free(in);
}
*count = lines;
return arr;
}
I have a variable length string that I am trying to divide from plus signs and study on:
char string[] = "var1+vari2+varia3";
for (int i = 0; i != sizeof(string); i++) {
memcpy(buf, string[0], 4);
buf[9] = '\0';
}
since variables are different in size I am trying to write something that is going to take string into loop and extract (divide) variables. Any suggestions ? I am expecting result such as:
var1
vari2
varia3
You can use strtok() to break the string by delimiter
char string[]="var1+vari2+varia3";
const char delim[] = "+";
char *token;
/* get the first token */
token = strtok(string, delim);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, delim);
}
More info about the strtok() here: https://man7.org/linux/man-pages/man3/strtok.3.html
It seems to me that you don't just want to want to print the individual strings but want to save the individual strings in some buffer.
Since you can't know the number of strings nor the length of the individual string, you should allocate memory dynamic, i.e. use functions like realloc, calloc and malloc.
It can be implemented in several ways. Below is one example. To keep the example simple, it's not performance optimized in anyway.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
char** split_string(const char* string, const char* token, int* num)
{
assert(string != NULL);
assert(token != NULL);
assert(num != NULL);
assert(strlen(token) != 0);
char** data = NULL;
int num_strings = 0;
while(*string)
{
// Allocate memory for one more string pointer
char** ptemp = realloc(data, (num_strings + 1) * sizeof *data);
if (ptemp == NULL) exit(1);
data = ptemp;
// Look for token
char* tmp = strstr(string, token);
if (tmp == NULL)
{
// Last string
// Allocate memory for one more string and copy it
int len = strlen(string);
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
++num_strings;
break;
}
// Allocate memory for one more string and copy it
int len = tmp - string;
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
// Prepare to search for next string
++num_strings;
string = tmp + strlen(token);
}
*num = num_strings;
return data;
}
int main()
{
char string[]="var1+vari2+varia3";
// Split the string into dynamic allocated memory
int num_strings;
char** data = split_string(string, "+", &num_strings);
// Now data can be used as an array-of-strings
// Example: Print the strings
printf("Found %d strings:\n", num_strings);
for(int i = 0; i < num_strings; ++i) printf("%s\n", data[i]);
// Free the memory
for(int i = 0; i < num_strings; ++i) free(data[i]);
free(data);
}
Output
Found 3 strings:
var1
vari2
varia3
You can use a simple loop scanning the string for + signs:
char string[] = "var1+vari2+varia3";
char buf[sizeof(string)];
int start = 0;
for (int i = 0;;) {
if (string[i] == '+' || string[i] == '\0') {
memcpy(buf, string + start, i - start);
buf[i - start] = '\0';
// buf contains the substring, use it as a C string
printf("%s\n", buf);
if (string[i] == '\0')
break;
start = ++i;
} else {
i++;
}
}
Your code does not have any sense.
I wrote such a function for you. Analyse it as sometimes is good to have some code as a base
char *substr(const char *str, char *buff, const size_t start, const size_t len)
{
size_t srcLen;
char *result = buff;
if(str && buff)
{
if(*str)
{
srcLen = strlen(str);
if(srcLen < start + len)
{
if(start < srcLen) strcpy(buff, str + start);
else buff[0] = 0;
}
else
{
memcpy(buff, str + start, len);
buff[len] = 0;
}
}
else
{
buff[0] = 0;
}
}
return result;
}
https://godbolt.org/z/GjMEqx
I'm trying to implement a C function that takes a string and then breaks that string on a certain character and returns back an array of strings after the split along with the size of that array. I'm using a data structure for this since returning a 2D array (the array of strings after the split) and its length is not possible. My code is given below:
struct charArr {
char *arr[10000];
int size;
};
struct charArr *stringSplitter(char *str, char c) {
struct charArr *splitString = (struct charArr *)malloc(sizeof(struct charArr));
if (splitString == NULL) {
fprintf(stderr, "malloc failed\n");
exit(1);
}
splitString->size = 0;
int i = 0;
int j = 0;
while (str[i] != '\0') {
if (str[i] == c) {
splitString->arr[splitString->size][j] = '\0';
(splitString->size)++;
j = 0;
i++;
while (str[i] == c) { /* this loop is to ignore continuous occurrences of the character c */
i++;
}
} else {
splitString->arr[splitString->size][j] = str[i];
i++;
j++;
}
}
splitString->arr[splitString->size][j] = '\0';
return splitString;
}
int main(int argc, char *argv[]) {
// take input from command line
if (argc == 1) {
//buffer to store lines
size_t buffer_size = 128;
char *buffer = malloc(buffer_size * sizeof(char));
if (buffer == NULL) {
fprintf(stderr, "malloc failed\n");
exit(1);
}
// loop continuously till user exits by ctrl+c
while (1) {
printf("Enter Input> ");
getline(&buffer, &buffer_size, stdin);
char *str = strdup(buffer);
struct charArr *splitString = stringSplitter(str, '&');
for (int i = 0; i<splitString->size; i++) {
printf("%s ", splitString->arr[i]);
}
}
}
return 0;
}
On running the code on a simple input like (the input is continuously taken from the command line):
Enter Input> this & that
I expect the output to be:
this that
But, I'm getting the error:
Segmentation fault (core dumped)
If the input is as shown below (i.e; continuous occurrences of the splitting character):
Enter Input> this &&& that
then also the output must be:
this that
Edit: I'm trying to extend this to split a string on multiple delimiters as well (in one go), so instead of char c in the above function, if char *c is passed which is a string of delimiters (example c = " \t\n" to remove all white spaces from given string), then also it should work as expected and return an array of strings after the split and length of array.
For example, if input is (multiple spaces, tabs and newline):
Enter Input> this that
Then the array returned (which is a part of the returned structure) must be of size 2 and only contain the 2 strings - "this" and "that".
Here's a rewrite of your function with the corrections that you need for proper allocation of each found string using strdup():
You can find my modifications preceded with comments that start 'Previously':
struct charArr* stringSplitter(char *str, char c){
struct charArr* splitString = (struct charArr*)malloc(sizeof(struct charArr));
char buffer[ MAX_BUFF ] ;
if(splitString == NULL){
fprintf(stderr, "malloc failed\n");
exit(1);
}
splitString->size = 0;
int i=0;
int j=0;
while(str[i] != '\0'){
if(str[i] == c){
//Previously: splitString->arr[splitString->size][j] = '\0';
splitString->arr[splitString->size] = strndup( buffer , j );
(splitString->size)++;
j = 0;
i++;
while(str[i] == c){ /* this loop is to ignore continuous occurrences of the character c */
i++;
}
} else {
// Previously: splitString->arr[splitString->size][j] = str[i];
buffer[j] = str[i];
i++;
j++;
}
}
//Previously: splitString->arr[splitString->size][j] = '\0';
splitString->arr[splitString->size++] = strndup( buffer , j );
return splitString;
}
It's been a long time since I wrote any C so I thought this would be a challenge. Here's a rewrite of the stringSplitter function.
struct charArr* stringSplitter(char *str, char c){
struct charArr* splitString = (struct charArr*)malloc(sizeof(struct charArr));
if(splitString == NULL){
fprintf(stderr, "malloc failed\n");
exit(1);
}
splitString->size = 0;
char sep[2];
sep[0] = c;
sep[1] = (char) 0;
char* next;
while( (next = strtok( str, sep )) )
{
str = NULL;
splitString->arr[ splitString->size++ ] = next;
}
return splitString;
}
Above, I'm simply using strtok. Take a look at the manpage for strtok() to see it's nuances.
I want to dynamically allocate only a portion of a character array.
So part of an array of size 100 is concrete. Say 10 is permanent memory, the other 90 is dynamic memory.
I made some attempt to read character by character until I decided to give up and take a shortcut idea I thought would work. However I end up getting an error that is
incorrect checksum for freed object - object was probably modified
after being freed
I use this method in a while loop in main and I pretty much free everything after the while loop processes. Because, I have the declaration outside of the while loop. I wanted to read an object in a while loop session since these objects end up being added into a list of objects. However the scope of the while loop causes segmentation problems, it cannot remember anything about the object. (I digress).
Here is my attempt.
Object* read(char* str)
{
Object* object = (Object*)malloc(sizeof(*object));
object->identity[0] = 0;
int capacity = (100 + 1) - (10);
object->name = (char*)malloc(capacity * sizeof(*object->name));
object->value = 0.0;
int length = strlen(str);
if (length > capacity)
object->name = (char*)realloc(object->name, (capacity * 2) * sizeof(*object->name));
int arguments = sscanf(str, "%" STRING_SPACE "s %lf %[^\n]s",
object->identity,
&object->value,
object->name);
if (arguments == MATCHER) {
return object;
} else {
return NULL;
}
return object;
}
In this case, an object has a variable sized name but a fixed amount of space allocated for its identity.
I tried something else with sscanf but realized it will never work because I read the string too late to assign memory to name. See;
/*
int len = 0;
for (char* itemObserve = item->name; *itemObserve; itemObserve++) {
if (len == sizeof(item->name)) {
capacity *= MULTIPLIER;
item->name = (char*)realloc(item->name, capacity * sizeof(*item->name));
}
len++;
}
*/
Here is the code in main, everything undefined is probably irrelevant to the bug:
int main()
{
FILE* stream;
Object* object;
ObjectList* list = initList();
while (true) {
char* line;
char cmd[15] = {0};
char* arg;
char* rest;
printf("> ");
line = getline(stdin);
arg = (char*)malloc(35 * sizeof(*arg));
rest = (char*)malloc(35 * sizeof(*rest));
int arguments = sscanf(line, "%s %s %[^\n]", cmd, arg, rest);
free(line);
line = NULL;
printf("\n");
if (strcmp(cmd, "add") == 0) {
arg = (char*)realloc(arg, (35 * 2) * sizeof(*arg));
sprintf(arg, "%s %s", arg, rest);
if ((object = read(arg)) == NULL) {
continue;
}
objectListAdd(list, object);
} else {
free(rest);
free(arg);
exit(EXIT_SUCCESS);
}
free(rest);
free(arg);
}
freeObject(object);
freeObjectList(list);
return EXIT_SUCCESS;
}
Separate getline function in main file
char* getline(FILE* stream)
{
int capacity = LINE_MAX + 1;
char* buffer = (char*)malloc(capacity * sizeof(*buffer));
int len = 0;
int ch;
while ((ch = fgetc(stream)) != '\n' && (ch != EOF)) {
if (len == capacity) {
capacity *= MULTIPLIER;
buffer = (char*)realloc(buffer, capacity * sizeof(*buffer));
}
buffer[len++] = ch;
}
if (ch == EOF) {
return NULL;
}
buffer[len] = '\0';
if (buffer == NULL)
return NULL;
return buffer;
}
There are other conditionals which work as a kind of command switch but they are irrelevant to the errors my program is exhibiting. This much I have narrowed the problem down to.
I want to make a function that reads a line of your choice, from a given text file. Moving on to the function as parameters (int fd of the open, and int line_number)
It must do so using the language C and Unix system calls (read and / or open).
It should also read any spaces, and it must not have real limits (ie the line must be able to have a length of your choice).
The function I did is this:
char* read_line(int file, int numero_riga){
char myb[1];
if (numero_riga < 1) {
return NULL;
}
char* myb2 = malloc(sizeof(char)*100);
memset(myb2, 0, sizeof(char));
ssize_t n;
int i = 1;
while (i < numero_riga) {
if((n = read(file, myb, 1)) == -1){
perror("read fail");
exit(EXIT_FAILURE);
}
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
numero_riga++;
int j = 0;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return myb2;
}else{
myb2[j] = myb[0];
j++;
}
}
return myb2;
}
Until recently, I thought that this would work but it really has some problems.
Using message queues, the string read by the read_line is received as a void string ( "\0" ). I know the message queues are not the problem because trying to pass a normal string did not create the problem.
If possible I would like a fix with explanation of why I should correct it in a certain way. This is because if I do not understand my mistakes I risk repeating them in the future.
EDIT 1. Based upon the answers I decided to add some questions.
How do I end myb2? Can someone give me an example based on my code?
How do I know in advance the amount of characters that make up a line of txt to read?
EDIT 2. I don't know the number of char the line have so I don't know how many char to allocate; that's why I use *100.
Partial Analysis
You've got a memory leak at:
char* myb2 = (char*) malloc((sizeof(char*))*100);
memset(myb2, 0, sizeof(char));
if (numero_riga < 1) {
return NULL;
}
Check numero_riga before you allocate the memory.
The following loop is also dubious at best:
int i = 1;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
You don't check whether read() actually returned anything quick enough, and when you do check, you leak memory (again) and ignore anything that was read beforehand, and you don't detect errors (n < 0). When you do detect a newline, you simply add 1 to i. At no point do you save the character read in a buffer (such as myb2). All in all, that seem's pretty thoroughly broken…unless…unless you're trying to read the Nth line in the file from scratch, rather than the next line in the file, which is more usual.
What you need to be doing is:
scan N-1 lines, paying attention to EOF
while another byte is available
if it is newline, terminate the string and return it
otherwise, add it to the buffer, allocating space if there isn't room.
Implementation
I think I'd probably use a function get_ch() like this:
static inline int get_ch(int fd)
{
char c;
if (read(fd, &c, 1) == 1)
return (unsigned char)c;
return EOF;
}
Then in the main char *read_nth_line(int fd, int line_no) function you can do:
char *read_nth_line(int fd, int line_no)
{
if (line_no <= 0)
return NULL;
/* Skip preceding lines */
for (int i = 1; i < line_no; i++)
{
int c;
while ((c = get_ch(fd)) != '\n')
{
if (c == EOF)
return NULL;
}
}
/* Capture next line */
size_t max_len = 8;
size_t act_len = 0;
char *buffer = malloc(8);
int c;
while ((c = get_ch(fd)) != EOF && c != '\n')
{
if (act_len + 2 >= max_len)
{
size_t new_len = max_len * 2;
char *new_buf = realloc(buffer, new_len);
if (new_buf == 0)
{
free(buffer);
return NULL;
}
buffer = new_buf;
max_len = new_len;
}
buffer[act_len++] = c;
}
if (c == '\n')
buffer[act_len++] = c;
buffer[act_len] = '\0';
return buffer;
}
Test code added:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
extern char *read_nth_line(int fd, int line_no);
…code from main answer…
int main(void)
{
char *line;
while ((line = read_nth_line(0, 3)) != NULL)
{
printf("[[%s]]\n", line);
free(line);
}
return 0;
}
This reads every third line from standard input. It seems to work correctly. It would be a good idea to do more exhaustive checking of boundary conditions (short lines, etc) to make sure it doesn't abuse memory. (Testing lines of lengths 1 — newline only — up to 18 characters with valgrind shows it is OK. Random longer tests also seemed to be correct.)