Debugger gives a segmentation error for strlen - c

In the code below the debugger shows no error but when I run this piece of code inside a function scope char *s is also in the function scope the debugger gives a segmentation error for the strlen function. Would adding char *s as a parameter solve the problem? Or is it something else?
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <locale.h>
#define SIZE1 100
#define SIZE2 2000
int main() {
const char *getFileExtension(const char *filename);
char tags[100][2000];
char files[100][2000];
char paths[100][2000];
char textfiles[100][2000];
char orph[100][2000];
int i, j, k = 0;
char *s;
for (i = 0; i < SIZE1; i++) {
if (strncmp(getFileExtension(files[i]), "txt", 3) == 0) {
strcpy(textfiles[k], files[i]);
k++;
}
}
k = 0;
for (i = 0; i < SIZE1; i++) {
for (j = 0; j < SIZE1; j++) {
if (strcmp(tags[i], textfiles[j]) != 0) {
snprintf(s, strlen(tags[i]), "%s", tags[i]);
s[strlen(s) - 1] = '\0';
strcpy(orph[k], s);
k++;
}
}
}
return 0;
}
const char *getFileExtension(const char *filename) {
const char *dot = strrchr(filename, '.');
if (!dot || dot == filename)
return "";
return dot + 1;
}
EDIT: after initializing char *s and the other arrays I ran my code on devc++ and www.onlinegdb.com. It kept giving me a segmentation fault on devc++ but the code worked on the website.

You declared uninitialized arrays
char tags[100][2000];
char files[100][2000];
char paths[100][2000];
char textfiles[100][2000];
char orph[100][2000];
So using them in standard C string functions like for example
if(strcmp(tags[i],textfiles[j])!=0)
{
snprintf(s,strlen(tags[i]),"%s",tags[i]);
invokes undefined behavior.
It seems the function getFileExtension also does not set elements of the array files in this call.
getFileExtension(files[i])
Also the pointer s
char *s;
used in this statement
snprintf(s,strlen(tags[i]),"%s",tags[i]);
also has an indeterminate value.

your tags array is not initialized. so strlen has undefined behavior. snprintf requires the size of available space not the length of the (uninitialized) contents. you should use sizeof instead of strlen in the snprintf call.
The 2nd argument to snprintf is the size which was allocated to the first argument. But you allocated nothing.

Related

Print function print some strange chars

i'm trying to create a random strings using this function:
static char *rand_string(char *str)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK";
int i;
for ( i = 0; i < 10; i++)
{
int key = rand() % (int) (sizeof charset - 1);
str[i] = charset[key];
}
str[11] = '\0';
return str;
}
The problem is this: sometimes when i am going to print the pointer, it display some strange char like this:
As you can see in the first launch the chars in a string are 10, in the second and third launch the chars in a string are 11...
This is my program:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
static char *rand_string(char *str);
int main()
{
char *string, //str
*string_result; //str1
int dimensione= 15,
i;
for(i=0;i<dimensione;i++)
{
string_result = rand_string(string);
printf("%s\n", string_result);
}
}
static char *rand_string(char *str)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK";
int i;
for ( i = 0; i < 10; i++)
{
int key = rand() % (int) (sizeof charset - 1);
str[i] = charset[key];
}
str[11] = '\0';
return str;
}
You can view and test my code here --> https://onlinegdb.com/r1yY8DWc8
Your whole code invoke undefined behavior, because you are passing string which is an uninitialized pointer which may "not" be guaranteed to accessible for the 11 bytes your are accessing in the rand_string() function.
You need to allocate memory from the main() and pass that buffer to be filled by the random string generator function, that way you have control of the memory you are modifying.
Also the for loop in your generator already fills indices from 0 to 9. To set the final byte to NULL, you need to use the index as 10.
Also the headers time.h and unistd.h are useless here. Here is a re-write of the same program with memory allocated through malloc(). Also modified your function rand_string() to void instead of returning a string.
#include <stdio.h>
#include <stdlib.h>
void rand_string(char *str);
int main()
{
int dimensione= 15;
char *string = malloc(11 * sizeof *string); // extra byte for NULL
if (!string) return 1;
int i;
for(i=0;i<dimensione;i++)
{
rand_string(string);
printf("%s\n", string);
}
free(string);
return 0;
}
void rand_string(char *str)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK";
int i;
for ( i = 0; i < 10; i++)
{
int key = rand() % (int) (sizeof charset - 1);
str[i] = charset[key];
}
str[10] = '\0';
}
Always compile with extra flags to enable all sorts of warnings from your compiler. For e.g. with gcc always add -Wall -Wextra to see the warnings that you could fix from your side.

Difference between char array[100] and char *array when calling functions?

i'd like to know why this code works fine with char tab[100] but doesn't work if I use char *tab ? fgets function takes a char* array as a parameter right ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Int Palindrome(char* str, int i, int j);
int main()
{
char tab[100];
printf("Enter your string : \n");
fgets(tab, 100, stdin);
int j = strlen(tab);
printf("%d\n", Palindrome(tab, 0, j - 2));
return 0;
}
int Palindrome(char* str, int i, int j)
{
if (i >= j)
{
printf("My word is a Palindrome !\n");
return printf("<(^w^)>\n");
}
else if (str[i] != str[j])
{
printf("My word is not a Palindrome !\n");
return printf("<(X.X)>\n");
}
else
{
return Palindrome(str, i + 1, j - 1);
}
}
With "not work" you probably mean you get some serious error reported like a segmentation fault.
The difference between char tab[100] and char *tab is that the first has storage allocated and the second hasn't. When you call a function with an array as a parameter, then the compiler passes a pointer to the first element of the array, so for the function that got called it doesn't see the difference whether it is called with an array-parameter or with a pointer-parameter.
So to let your program work with char *tab; you must first allocate storage to this pointer, such as with char *tab=malloc(100); Now that there is valid storage allocated (and the pointer now points to it), you can call your function with this tab as parameter.

imitate strcpy function in c using char pointers

I am try to write a user defined function which will do exactly what strcpy() library function do. But although there is no error, my program crashes and not copying second string to first string. What's wrong with this code and how to fix it?
#include<stdio.h>
#include<string.h>
int main(){
char *ch1="abcd";
char *ch2="efgh";
str_cpy(ch1,ch2);
}
str_cpy(char *c1,char *c2){
int i=0;
while(c1[i]!='\0'){
i++;
}
printf("%c",*(c1+3));
int k;
for(k=0;k<=i;k++){
*(c1+k)=*(c2+k);
}
}
String literals are generally put into read only area, that's why the program crashed when you are writing into c1. The destination string needs to be an array or allocated buffer:
char c1[5];
str_cpy(c1, c2);
Also, in the function, it looks you are copying c2 to c1, but you are counting the length of c1, you should count the length of c2 instead:
// copy string c2 to c1
void str_cpy(char *c1, const char *c2){
int i=0;
while(c2[i]!='\0'){
i++;
}
int k;
for(k=0;k<=i;k++){
*(c1+k)=*(c2+k);
}
}
Your program invokes undefined behavior because you are trying to write to a string literal. String literals can be stored in read only memory, which is probably the case on your system, hence causing a crash.
Note that your string copying function can perform the copy in a single loop:
char *str_cpy(char *c1, const char *c2) {
for (int i = 0;; i++) {
c1[i] = c2[i];
if (c1[i] == '\0')
return c1;
}
}
You can verify the behavior with a modified main:
#include <stdio.h>
char *str_cpy(char *c1, const char *c2) {
for (int i = 0;; i++) {
c1[i] = c2[i];
if (c1[i] == '\0')
return c1;
}
}
int main(void) {
char buf[20];
char *ch2 = "Hello world\n";
printf("%s\n", str_cpy(buf, ch2));
return 0;
}
Here is a possible rework of your code, which doesn't have to pre-define buffer size (c1). You simply pass the buffer address. Also, please note that such buffer has to be freed once used (for example, if declared in local scope, not in main()):
#include <stdio.h>
#include <stdlib.h>
char *str_cpy(char **c1, const char *c2) {
int i, size = 0;
for(i = 0; ; i++)
if(c2[i] == '\0')break;
size = i + 1;
if(!(*c1 = realloc(*c1,size*sizeof(char))))
return *c1;//or devise some more sophisticated error handling
for (i = 0;; i++) {
(*c1)[i] = c2[i];
if (c2[i] == '\0')
return *c1;
}
}
int main(void){
char *ch1 = malloc(1); //you're responsible for freeing it, once used
char *ch2 = "Hello, everybody in the neighborhood!";
printf("%s\n",str_cpy(&ch1,ch2));
free(ch1);
return 0;
}
Please, also note you don't need to #include <string.h>

memory leakage on asprintf using inside a loop in C

I have a piece of code that looks like this
#include <stdio.h>
int main()
{
int i;
int number_of_chunks = 12;
char *final_string = NULL;
for(i = 0; i < number_of_chunks; i++)
{
char *chunk = some_hash_table.pop(i);
asprintf(&final_string, "%s%s", (final_string==NULL?"":final_string), chunk);
}
free(final_string);
return 0;
}
Here I am concatinating string chunks dynamically, meaning I don't know the size of each chunk in advance. For this I am using asprintf. The code works fine, however rise some serious memory issue. My doubt is asprintf allocates memory in each iteration and the code loses pointer in each iteration. If there is any other way I can concate string inside loop please guide me
To put your question in the simplest possible way, what you are essentially trying to do with the above code is
1. Allocate memory to a pointer continuously(in your case 12 times in the for loop) and
2. free it at the end only once, which is causing memory leak.
Like in the below code
#include <stdio.h>
int main()
{
int i;
int number_of_chunks = 12;
char *final_string = NULL;
for(i = 0; i < number_of_chunks; i++)
{
/*For example: similar to what asprintf does, allocate memory to the pointer*/
final_string = malloc(1);
}
free(final_string);
return 0;
}
From the above example it is easily visible that you have allocated the memory 12 times but freed only once.
code snippet:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
int number_of_chunks = 12;
char *final_string = NULL;
char *tmp = NULL;
for(i = 0; i < number_of_chunks; i++)
{
char *chunk = some_hash_table.pop(i);
asprintf(&final_string, "%s%s", (tmp==NULL?"":tmp), chunk);
if (tmp)
free(tmp);
tmp = final_string;
}
printf("%s\n", final_string);
free(final_string);
return 0;
}
Others have already pointed out that you lose the reference to all but the last allocation and that having the same string that is written to as printf argument is probably undefined behaviour, even more so as re-allocations might occur and invalidate the format argument.
You don't use asprintf's formatting capabilities, you use it only to concatenate strings, so you might want to take another approach. You could either collect the strings in an array, determine the needed length, allocate as appropriate and fill the allocated buffer with memcpy.
Or you could write a self-allocating string buffer similar to C++'s std::stringstream, for example:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct append_t {
char *str; /* string */
size_t len; /* length of string */
size_t size; /* allocated size */
};
void append(struct append_t *app, const char *str)
{
size_t len = strlen(str);
while (app->len + len + 1 >= app->size) {
app->size = app->size ? app->size * 2 : 0x100;
app->str = realloc(app->str, app->size);
/* error handling on NULL re-allocation */
}
strcpy(app->str + app->len, str);
app->len += len;
}
int main(int argc, char **argv)
{
struct append_t app = {NULL};
for (int i = 1; i < argc; i++) {
append(&app, argv[i]);
}
if (app.str) puts(app.str);
free(app.str);
return 0;
}

Dynamic and static char array

Here are the codes of a program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * cloning(char * q){
char s[strlen(q)];
int i;
for(i = 0; i < strlen(q); i++)
s[i] = q[i];
return s;
}
int main(){
char q[] = "hello";
char *s = cloning(q);
return 0;
}
After the compilation a warning appears, so I changed the returned value like this:
char *b = s;
return b;
In this way the warning can be solved. However I found that inside the function cloning(), sizeof(s) is 5, but strlen(s) is 7. And if I change char s[strlen(q)] simply to char s[5], the output is still incorrect. Can anybody explain this problem to me? Thank you very much.
char s[strlen(q)] is a local variable, and hence when you return its address, it results in undefined behaviour. Thus either you could use strdup() or malloc() to dynamically allocate the array, thus ensuring that the array s is available on the heap when you return from the function. The returned array would need to be free()-ed as well, else it would have a memory leak :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * cloning(char * q){
char *s = malloc(strlen(q)+1);
// if you write char s[strlen(q)], it is defined locally, and thus on return gives an undefined behaviour
int i;
for(i = 0; i < strlen(q)+1; i++)
s[i] = q[i];
return s;
}
int main(){
char q[] = "hello";
char *s = cloning(q);
free(s);
return 0;
}
char s[strlen(q)];
is a variable-length array. Like a malloc'ed buffer its size is determined at runtime. Unlike a malloc'ed buffer, it ceases to exist when the function returns.
multiple issues with this code:
char * cloning(char * q){
char s[strlen(q)]; // s has strlen size but needs strlen + 1 to hold \0
int i;
for(i = 0; i < strlen(q); i++) // should copy the \0 otherwise q is not a valid string
s[i] = q[i];
return s;// returns the address of a local var == undef. behavior
}
if you want to clone a string just do strdup()
char* cloning(char* q)
{
return strdup(q);
}
or the equivalent
char * cloning(char * q)
{
char* s = malloc(strlen(q)+1);
int i;
for(i = 0; i < strlen(q)+1; i++)
s[i] = q[i];
return s;
}
The proper way to do this with standard C, no matter version of the C standard, is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cloning (const char* str)
{
char* clone;
size_t size = strlen(str) + 1;
clone = malloc(size);
if(clone == NULL)
{
return NULL;
}
memcpy(clone, str, size);
return clone;
}
int main(){
char original[] = "hello";
char* clone = cloning(original);
if(clone == NULL)
{
puts("Heap allocation failed.");
return 0;
}
puts(clone);
free(clone);
return 0;
}
Dynamic arrays in C are declared using Malloc and Calloc. Try googling it.
Eg:
char *test;
test = (char *)malloc(sizeof(char)*Multiply_By);
In C,static array is in stack,after function return,it's been destoryed. and string with char has a '\0' end. But strlen don't include it. For example.char q[] = "hello"; strlen(q) = 5,but the real size is 6
If you want to copy a string, the last '\0' must be added at the end.or using
char *s = malloc(sizeof(q)); ...; for(i = 0; i < sizeof(q); i++)
s[i] = q[i];
you also need to free it after using.Maybe become a mem leak.
Hope this can help u.

Resources