Reading string line by line causes buffer overflow - c

This is the code I am trying to run, I should read a sequence of strings line by line.
int i;
char buf[100];
int o_size = 16;
char *output = malloc(o_size * sizeof(char));
strcpy(output, "");
for(i = 0; i < n; i++){
fgets(buf, 100, stdin);
strtok(buf,"\n");
char temp[100];
strcpy(temp, buf);
strtok(temp, " "); // The instruction is stored inside the temp variable
char temp1[100];
strcpy(temp1, strchr(buf, ' ') + 1);
strcpy(buf, temp1); // The input string is stored inside the buf variable (or the index line in the check case)
int h_val = poly_hash(buf, x, p, m);
if(!strcmp(temp, "add")){
...
}
else if(!strcmp(temp, "del")){
...
}
else if(!strcmp(temp, "find")){
...
}
else if(!strcmp(temp, "check")){
...
}
}
I also wrote a function to append to the output string, could this be the cause for the buffer overflow?
void to_output(char **output, int *o_size, char *string){
if(strlen(*output) + strlen(string) >= *o_size){
*o_size *= 2;
char *temp = malloc(*o_size * sizeof(char));
strcpy(temp, *output);
*output = realloc(*output, *o_size * sizeof(char));
strcpy(*output, temp);
free(temp);
}
strcat(*output, string);
}

Simpler is:
void to_output(char **output, int *o_size, char *string){
int outlen = strlen(*output) + strlen(string) + 1;
if (outlen > *o_size) {
*output = realloc(*output, outlen);
*o_size = outlen;
}
strcat(*output, string);
}

Related

Copying specific number of characters from a string to another

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

String pointer in C prints weird symbol

I was having some difficulties when trying to print out the string pointer after dynamically insert a character at the front of char array.
The parameter *str is a dynamic char array from my main whereas the input is a single character which should append to the first element of the dynamic array after executing the insert().
int main(){
//code snippet. I removed other part to keep the question short
printf("How many characters do you want to input: ");
scanf("%d", &n);
str = malloc(n + 1);
printf("Input the string class: ");
scanf("%s", str);
//switch statement
case '1':
printf("What is the character you want to insert: ");
scanf(" %c", &input);
insert(&str, input);
break;
}
return 0;
}
void insert(char *str, char input) {
char *new_str;
int i, len = strlen(str);
new_str = malloc(len + 1);
new_str[0] = input;
strncpy(&new_str[1], str, len - 1);
new_str[len] = 0;
for (i = 0; i < len; i++) {
printf("%c", new_str[i]);
}
}
When I tried to loop thru the new_str and print out the string array, it gives me weird symbols and I have no idea what are they. Any ideas?
EDIT
The expected output as below:
How many characters do you want to input: 5
Input the string:datas
The string is: datas
Do you want to 1-insert or 2-remove or 3-quit?: 1
What is the character you want to insert: a
Resulting string: adata
The output I am getting:
Alternative version, avoiding any string copy functions. (Since, alter the strlen() you already know the string length to copy, you don't need any more string functions)
char * insert_a_character(char * str, char ch)
{
char * new;
size_t len;
if (!str) return NULL;
len = strlen(str);
new = malloc (1+len+1);
if (!new) retun NULL;
new[0] = ch;
memcpy(new+1, str, len);
new[len+1] = 0;
return new;
}
I assume that the caller will free if required for orig
char * insert(char *orig, char input) {
char * new_str = malloc(strlen(orig) + 2); // An extra one for null
strcpy(new_str + 1, orig);
new_str[0] = input;
printf("%s", new_str); // To print it out
return new_str; // The caller needs to free this;
}
That should work.
Assembling all comments:
void insert(char *str, char input) {
char *new_str;
int i, len = strlen(str);
new_str = malloc(len + 2);
new_str[0] = input;
strcpy(new_str+1, str);
new_str[len+1] = 0;
for (i = 0; i <= len; i++) {
printf("%c", new_str[i]);
}
}
Of course you still need to do something with the new string, such as returning it or freeing it.

compressing the lines of a file using dynamic memory

i need to make a function that returns a compressed line with the following formats,
input:
pprrrinnnttttfff
output:
p2r3i1n3t4f3
and if the new string is larger than the original, return the original, can someone tell what is wrong with my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *comprimir(char *s);
int main(){
FILE* input;
char *lineptr = NULL;
size_t len=0, c;
input =fopen ("input.dat", "r");
while ((c = getline(&lineptr, &len, input))!= -1){
lineptr = comprimir(lineptr);
printf("%s", lineptr );
}
fclose(input);
}
char* comprimir (char *s){
int len1 = strlen(s), len2=0;
char *str, *in, *mystr;
mystr =(char*) calloc(len1*2, sizeof(char));
strcpy(mystr, s);
for (str =mystr, in=mystr; *str; str++){
len2 += 2;
if (len2 >= len1) {
free(mystr);
return s;
}
int count =1;
in[0] = str[0]; printf("%s",in[0] ); in++;
if (len2 > len1) return s;
while (str[0] == str[1]){
count++;
str++;
}
in[0] = '0' + count;
in++; printf("%s", in[0] );
if (len2 > len1) return s;
}
strcpy(s, in);
free(mystr);
return s;
}
sample to fix
char* comprimir (char *s){
int len1 = strlen(s), len2=0;
char *out, *in, *mystr;
mystr =malloc(len1 + 2);//2*len1 not required, +2 : "r" -> "r1"(len + NUM_len + NUL
//`s` not copy to mystr, avoid overwriting
for (out = mystr, in=s; *in;){
int count = 1;
*out++ = *in++;//Pre-increment `in` to reduce code.
while (in[-1] == in[0]){
count++;
in++;
}
int num_len = sprintf(out, "%d", count);//OK even count is more than 10
len2 += 1 + num_len;
if (len2 >= len1) {
free(mystr);
return s;
}
out += num_len;
}
*out = 0;//terminate by '\0'
strcpy(s, mystr);
free(mystr);
return s;
}

Dynamic array of strings

I have to dynamically allocate array of words. Words are stored in a file separated by variable count of white-space characters. I don't know how many words is in the file a they can have variable length.
I have this code:
void readWord(FILE* stream, char *word, char first_c) {
word[0] = first_c;
char val;
int wlen = 1;
// isWhitespac is my function - tests if char is blank or '\n'
while ((val = fgetc(stream)) != EOF && isWhitespace(val) == 0) {
wlen++;
word = realloc(word, (wlen+1) * sizeof (char));
word[wlen-1] = val;
}
word[wlen] = '\0';
}
int readList(const char *file) {
FILE* f;
char **arr;
char val;
int wcount = 0;
arr = malloc(sizeof (char*));
f = fopen(file, "r");
while (fscanf(f, " %c", &val) == 1) {
wcount++;
arr = realloc(arr, wcount * sizeof (char *));
arr[wcount - 1] = malloc(sizeof (char));
readWord(f, arr[wcount-1], val);
printf("%s\n", arr[wcount-1]);
}
for (int i = 0; i < wcount; ++i) {
free(arr[i]);
}
free(arr);
fclose(f);
return 0;
}
It appears to work fine, it reads a prints all the words. But when I run the program with Valgrind the are too many errors, which I can't find. Could anyone help me? (I know I have to test if malloc and others went fine, it is just a test func.)
The Valgrind log is quite long, should I post it too?
One of the issues is that you do realloc inside readWord. If realloc allocates a new buffer and doesn't just extend the current one then your code will crash (you will double free the pointer) and this is what Valgrind picks up. To fix this I would rewrite the code so it returns a pointer instead of void.
char * readWord(FILE* stream, char *word, char first_c) {
word[0] = first_c;
char val;
int wlen = 1;
// isWhitespac is my function - tests if char is blank or '\n'
while ((val = fgetc(stream)) != EOF && isWhitespace(val) == 0) {
wlen++;
word = realloc(word, (wlen+1) * sizeof (char));
word[wlen-1] = val;
}
word[wlen] = '\0';
return word;
}
And then change the loop in readList to this:
while (fscanf(f, " %c", &val) == 1) {
wcount++;
arr = realloc(arr, wcount * sizeof (char *));
arr[wcount-1]=malloc(sizeof(char));
arr[wcount - 1] = readWord(f, arr[wcount-1], val);
printf("%s\n", arr[wcount-1]);
}

Function only works once - C

I've been trying to make a basic XOR header file for use in some future programs. So far I've gotten almost everything to work, but I can't seem to use the same function twice. If I call the function to encrypt the string it works, but then if I call it again it crashes. I don't know if I'm doing something wrong memory-wise or am missing something obvious. Hope someone can point out a flaw in this because I can't seem to find anything wrong.
Edit: If posting this much is too much, feel free to trim the code. I already took out quite a bit, so I'm not just pasting my project and hoping someone fixes it.
// Main.c
#define MAX_LENGTH 255
#define KEY_SIZE 8
int main(int argc, char *argv[]) {
//Get String to XOR
char *input = malloc (MAX_LENGTH);
printf("Enter a string to encrypt: ");
fgets(input, MAX_LENGTH, stdin);
if(input[strlen (input) - 1] == '\n') {
input[strlen (input) - 1] = '\0';
}
//Create a random key
char *pass = _create_key(KEY_SIZE);
int len = strlen (input);
printf("Length of key is %d\n", KEY_SIZE);
printf("Entered String: %s - Password: %s\n", input, pass);
//Encrypt works fine
char *encrypted = malloc (sizeof (input));
_xor_str_s(input, pass, len, encrypted);
printf("Encrypted String: %s\n", encrypted);
char *decrypted = malloc (sizeof (input));
//Crashes here
_xor_str_s(encrypted, pass, len, decrypted);
printf("Decrypted String: %s\n", decrypted);
return 0;
}
//Header File Function
void _xor_str_s(char *str, char *pass, int len, char *out) {
int i = 0;
for(i = 0; i < len; i++) {
*(out + i) = str[i] ^ pass[i % strlen (pass)];
}
*(out + i) = 0;
}
char * _create_key(int len) {
len = !len ? 16 : len;
char *ret = (char *)malloc (len);
unsigned int _GLOBAL_SEED_ = (unsigned int)time(NULL);
srand (_GLOBAL_SEED_);
int i = 0;
for(i = 0; i < len; i++) {
ret[i] = (char)(rand() + 1); //+1 avoids NULL
}
ret[i] = '\0';
return ret;
}
char *encrypted = malloc (sizeof (input));
is probably the problem as this will always be sizeof(char *). I think you want
char *encrypted = malloc (strlen (input) + 1);

Resources