I try to program a simple implementation of ls for school
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int normalsort( const void *string1, const void *string2) {
char *const *char1 = string1;
char *const *char2 = string2;
return strcasecmp(*char1, *char2);
}
int listDir (char* path, int listToggeled, int classifyToggeled){
DIR *dir = opendir(path);
struct dirent *entry;
struct stat s;
char** listofentries;
char symbol = '-';
int counter = 0;
while ((entry = readdir(dir)) != NULL){
if (entry->d_name[0] != '.'){
listofentries = realloc(listofentries, (counter + 1) * sizeof(char*));
listofentries[counter] = entry->d_name;
counter++;
}
}
qsort(listofentries, counter, sizeof(char*), normalsort);
for (int i = 0; i < counter; i++){
char* entryname = listofentries[i];
if (entryname[0] != '.'){
printf("%s", entryname);
if (classifyToggeled == 1){
lstat(entryname, &s);
if (S_ISDIR(s.st_mode)) {
symbol = '/';
} else if (S_ISLNK(s.st_mode)) {
symbol = '#';
} else if ((S_ISREG(s.st_mode)) && (s.st_mode & S_IXUSR)) {
symbol = '*';
} else {
symbol = ' ';
}
printf("%c", symbol);
}
if (listToggeled == 1){
printf("\n");
}
else {
printf(" ");
}
}
}
closedir(dir);
return 0;
}
int main(int argc, char **argv) {
int classifyToggeled = 0;
int listToggeled = 0;
char* dirToList = ".";
if (argc == 1){
listDir(dirToList, listToggeled, classifyToggeled);
return 0;
}
for (int i = 1; i < argc; i++){
char* currentArg = argv[i];
//Check if -F is set
if (strcmp(currentArg, "-F") == 0 || strcmp(currentArg, "-1F") == 0 || strcmp(currentArg, "-F1") == 0){
classifyToggeled = 1;
}
//Check if -1 is set
if (strcmp(currentArg, "-1") == 0 || strcmp(currentArg, "-1F") == 0 || strcmp(currentArg, "-F1") == 0){
listToggeled = 1;
}
//List out all folders
if (currentArg[0] != '-'){
dirToList = currentArg;
}
}
//If no folders were listed yet, list current folder
//printf("dirtolist: %s", dirToList); <-- This line
listDir(dirToList, listToggeled, classifyToggeled);
if (listToggeled == 0){
printf("\n");
}
return 0;
}
It has a few bugs:
When the printf line marked above is not commented out, the program tells realloc(): invalid old size
When this line is commented out this only happens if the program is executed without any parameters
/bin/ and /sbin/ print out weird characters
I think this is some kind of memmory issue but I have hardly any C knowledge to just see it
Your code exhibits undefined behaviour because you passed a non-static, uninitialised pointer to realloc whose contents were indeterminate.
From C11, Memory Management Functions:
The realloc function deallocates the old object pointed to by ptr and
returns a pointer to a new object that has the size specified by size.
....if ptr does not match a pointer earlier returned by a memory
management function, or if the space has been deallocated by a call to
the free or realloc function, the behavior is undefined.
Possible fixes:
Initialize it with 0 / NULL.
Declare it as static.ยน
Replace it with a call to malloc.
The realloc function returns a pointer to the new object (which may
have the same value as a pointer to the old object), or a null pointer
if the new object could not be allocated.
realloc returns NULL on failure, your code should check for it.
#include <errno.h>
char *line = 0;
errno = 0;
char *new = realloc (line, size);
if (!new) {
perror ("realloc");
/* realloc() failed to allocate memory, handle error accordingly. */
}
The above code snippet can be rewritten as:
#include <errno.h>
errno = 0;
char *new = malloc (size);
if (!new) {
perror ("malloc");
/* malloc() failed to allocate memory, handle error accordingly. */
}
Similarly, opendir returns a NULL pointer while lstat returns -1 to indicate an error. Check for them.
[1] โ Objects declared with static storage duration and are always initialised. In the absence of a definition, they are implicitly initialised to 0.
From the C standard C11 6.7.9/10:
"... If an object that has static or thread storage duration is not
initialized explicitly, then:
โ if it has pointer type, it is initialized to a null pointer;
โ if it has arithmetic type, it is initialized to (positive or
unsigned) zero;"
Though, it's good practice to explicitly set it to 0.
Bugs:
listofentries isn't initialized, it must be set to NULL or you can't use realloc.
You don't check if realloc succeeded or not.
Related
I been trying to figure out why Valgrind reports unreachable memory and the buffer gets corrupted when i don't return the pointer (case 2) .
As i understand it i give read_input a pointer and it uses it. If realloc is caused i get a new pointer and replace the old one, so the pointer of input_buffer in main,and wherever there is that pointer it should have that new pointer, but it doesn't.
Is it maybe that i am passing literally the address ?
So the input_buffer in main has the old address as it was never changed? (My C is a bit rusty)
Is there a way to keep the input_buffer "updated" without returning the value like case 1 ? thus being able to write code like case 2 ?
(without having the buffer global/static)
#include "dev_utils.h"
#include "promt.h"
#include "sh_input.h"
int main(int argc, char *argv[]) {
// char *input_buff = (char *)malloc(CMD_BUFF * sizeof(char));
char *input_buff = (char *)malloc(1024 * sizeof(char));
if (!input_buff) {
fprintf(stderr, "Memory allocation failed at %s:%d! Exiting.\n",
"cs345sh.c", 8);
exit(1);
};
while (1) {
put_promt();
// 1. input_buff = read_input(input_buff);
// 2. read_input(input_buff);
parse_input(input_buff);
}
free(input_buff);
return 0;
}
#include "sh_input.h"
#include "dev_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *read_input(char *input_buff) {
unsigned int input_buffer_size = CMD_BUFF;
unsigned int input_index = 0;
char input;
while(1) {
input = getchar();
if (input_index >= input_buffer_size) {
input_buffer_size += CMD_BUFF;
char *new_buff;
new_buff = realloc(input_buff, input_buffer_size);
if (!new_buff) {
fprintf(stdout, "Memory allocation failed at %s:%d! Exiting.\n",
"sh_input.c", 17);
exit(1);
};
input_buff = new_buff;
}
if (input == EOF || input == '\n') {
input_buff[input_index] = '\0';
return input_buff;
} else {
input_buff[input_index] = input;
}
++input_index;
}
// 1. return input_buff;
}
void parse_input(char *input) {
if (strcmp(input, "exit") == 0) {
free(input);
exit(EXIT_SUCCESS);
}
printf("%s\n", input);
}
Function arguments are passed by value in C. The input_buff parameter is a different object than the variable that you pass into the function when you call it (they have different memory addresses, even though the pointer value stored at these two addresses is initially the same). Thus, updating the parameter variable has no effect on the variable in the caller function.
So the caller function must take care of updating its own variable, which you can achieve by returning the new pointer, or as #UnholySheep has already pointed out in the comments to your question, you could instead pass a pointer to the variable to overwrite it from within the read_input function.
char* GetCollection()
{
FILE *collection;
char val1[15] = "collection.txt";
collection = fopen(val1,"r");
char readingline[10];
char *listofurls[10];
*listofurls = malloc(10 * sizeof(char));
int j= 0,k,m=0,p, nov=0, q, r;
while (fscanf(collection, "%s", readingline)==1) {
listofurls[j] = malloc(10*sizeof(char));
strcpy(listofurls[j],readingline);
j++;
nov++;
}
for (k = 0 ; k < nov ; k++)
printf("%s\n", listofurls[k]);
fclose(collection);
return listofurls;
}
I want to return listofurls from GetCollection method and use it in main method. I am not able to catch the return value in main method.
You can't do that - though the memory it points to has lifetime beyond the scope of the function - the array has not. Array is of automatic storage duration. So you can't do that. Trying to access it outside the scope on which it is declared invokes Undefined behavior.
Easy solution, allocate the memory which contains the char*s dynamically. (Another would be to wrap the array inside a struct and then return it from the function).
#define MAXSIZE 10
...
...
char **listofurls;
listofurls = malloc(sizeof *listofurls * MAXSIZE);
if( !listofurls ){
perror("malloc");
exit(1);
}
...
return listofurls;
In fact it is not clear why you suddenly allocate memory for the 0th pointer in the array of pointer listofurls. There is a memory leak for that. You didn't check the return value of fopen. Check whether it is successful in opening the file or not.
And with the changes proposed the signature of the function would be
char** GetCollection();
With these changes you will hold the return value in main()
char** p = GetCollection();
And along with this you will free this allocated memory when you are done working with it.
If you really want to return an array, you can wrap it in a struct like this, but I prefer #coderredoc's malloc solution.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct MyStruct
{
char* listofurls[10];
};
struct MyStruct GetCollection()
{
FILE *collection;
char val1[15] = "collection.txt";
collection = fopen(val1,"r");
if (collection == NULL)
{
fprintf(stderr, "Unable to open file %s\n", val1);
exit(-1);
}
char readingline[10];
struct MyStruct myStruct;
int j= 0,k, nov=0;
while (fscanf(collection, "%s", readingline)==1) {
myStruct.listofurls[j] = malloc(10); //sizeof(char) is always 1
if (myStruct.listofurls[j] == NULL)
{
fprintf(stderr, "Unable to malloc for string %d\n", j);
}
else
{
strcpy(myStruct.listofurls[j],readingline);
}
j++;
nov++;
}
for (k = 0 ; k < nov ; k++)
printf("%s\n", myStruct.listofurls[k]);
fclose(collection);
return myStruct;
}
int main(void)
{
struct MyStruct myStruct = GetCollection();
for (int i=0; i<10; i++)
{
printf("%s\n", myStruct.listofurls[i]);
free(myStruct.listofurls[i]);
}
return 0;
}
And turn on compiler warnings, -Wall -Wextra should suffice .. you have several, including trying to return the local array. Always check the return value of function calls that could return errors (fopen, malloc)
hello friends :) i'm practicing C programming. in this program i have a task to make array of string. i have no idea what's wrong here...probably something about realloc, error i get is _crtisvalidheappointer
#define _CRT_SECURE_NO_WARNINGS
#define MAX 100
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readString(char **s)
{
int i = 0;
char c;
printf("\nInput string: ");
while ((c = getchar()) != '\n')
{
i++;
*s = realloc(*s, i*sizeof(char*));
if (*s == NULL) { printf("Memory allocation failed!"); exit(1); }
(*s)[i - 1] = c;
}
*s = realloc(*s, (i + 1)*sizeof(char));
if (*s == NULL) { printf("Memory allocation failed!"); exit(1); }
(*s)[i] = '\0';
}
char **load_words()
{
int cnt=0,wordcnt=0,i=0;
char **words = NULL, *input = NULL;
readString(&input);
while (input[cnt] != '\0' && cnt < strlen(input))
{
words = realloc(words, ++wordcnt);//errors in second repeat of the loop
words[wordcnt] = malloc(MAX);
i = 0;
while (input[cnt] != ' ')
{
words[wordcnt][i++] = input[cnt++];
}
words[wordcnt][i] = '\0';
realloc(words[wordcnt], (i + 1)*sizeof(char));
}
realloc(words, wordcnt);
free(input);
return words;
}
void main()
{
int i;
char **words = NULL;
words = load_words();
scanf("%d", &i);
}
can someone help me and tell me what did i do wrong here? this function should return array of strings but array should be double pointer(string matrix)
You need to change
words = realloc(words, ++wordcnt);
to
words = realloc(words, ++wordcnt * sizeof(*words));
Otherwise you are not allocating enough memory.
words[wordcnt] = malloc(MAX);
This also is not correct, you should access words[wordcnt-1].
You are using realloc but you're not saving its return value anywhere. This means the pointers you have still point to the memory that was freed and the newly allocated memory is leaked.
Look at the working function and you'll see how to use it properly.
One thing to realize when reallocating a double-pointer is that the size of type to realloc is always the sizeof (a pointer). It will be the same on any given system no matter the data type at issue. You can generically reallocate a double-pointer as follows:
/** realloc array of pointers ('memptr') to twice current
* number of pointer ('*nptrs'). Note: 'nptrs' is a pointer
* to the current number so that its updated value is preserved.
* no pointer size is required as it is known (simply the size
* of a pointer)
*/
void *xrealloc_dp (void *ptr, size_t *n)
{
void **p = ptr;
void *tmp = realloc (p, 2 * *n * sizeof tmp);
if (!tmp) {
fprintf (stderr, "xrealloc_dp() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE); /* or break; to use existing data */
}
p = tmp;
memset (p + *n, 0, *n * sizeof tmp); /* set new pointers NULL */
*n *= 2;
return p;
}
note: the memset call is optional, but useful if you have initialized all non-assigned pointers to NULL (such as when using NULL as a sentinel)
note2: you are free to pass a parameter setting the exact number of pointers to increase (elements to add) or change the multiplier for the current allocation as needed for your code.
i have a problem with the initialization of the values inside the first dynamic array of pointers
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char*** GetIndexes()
{
int n = 0;
char ***index;
printf("please insert the number of words you want to add to dictionary\n");
scanf("%d", &n);
index = (char***)calloc(n, sizeof(char));
if (index == NULL)
{
printf("allocation Failed");
return;
}
return index;
}
char** GetDefinitions()
{
int n = 0;
char **definition;
printf("please insert the number of defintions you want to add to the word\n");
scanf("%d", &n);
definition = (char**)calloc(n+1, sizeof(char));
if (definition == NULL)
{
printf("allocation failed");
return;
}
return definition;
}
int main()
{
char *** dptr = GetIndexes();
if (dptr == NULL)
{
printf("memory Allocation failed");
}
int indexcount = sizeof(dptr) / sizeof(char),i;
for (i = 0; i < indexcount; i++)
{
printf("word number %d\n", i + 1);
*dptr[i] = GetDefinitions();
}
printf("%p",dptr);
}
i tried running the debugger in VS2013 and after i enter the number of defintions i want it crashed with this message:
Unhandled exception at 0x01103FB0 in ConsoleApplication1.exe: 0xC0000005: Access violation writing location 0x00000000.
i missed an allocation of something but i cant quite figure out what i missed,
thanks in advance
Your program is very broken
You allocate n char ***s but only request space for n chars and also do it for char **, to prevent this kind of mistake you may use the sizeof operator this way
char ***index;
index = calloc(n, sizeof(*index));
and
char **definition;
definition = calloc(n, sizeof(*definition));
and as you see casting calloc makes it harder and it's not necessary.
You have a return statement that doesn't return anything an GetIndexes() as well as one in GetDefinitions.
They should return NULL if you want to handle failure in the caller function
return NULL;
You erroneously use the sizeof operator to determine the number of char *** pointer allocated in
int indexcount = sizeof(dptr) / sizeof(char)
this will be either 4 or 8 depending on the architecture i.e. the size of a pointer divided by 1 sizeof(char) == 1 always.
You can't compute that value, you simply have to keep track of it. The size
You dereference the triple pointer twice and try to assign a double pointer to it
*dptr[i] = GetDefinitions();
here the operator precedence is also an issue, but regardless of that, this is wrong, may be what you meant was
dptr[i] = GetDefinitions();
This is not going to make your program crash, but it's certainly important to free all malloced pointers before exiting the program.
Here is a suggestion for your code to work, ignore it's purpose since it's not clear what you are trying to do
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ***GetIndexes(unsigned int *count)
{
char ***index;
printf("please insert the number of words you want to add to dictionary > ");
scanf("%u", count);
index = calloc(*count, sizeof(*index));
if (index == NULL)
{
printf("allocation Failed");
return NULL;
}
return index;
}
char **GetDefinitions(unsigned int *count)
{
char **definition;
printf("please insert the number of defintions you want to add to the word > ");
scanf("%u", count);
definition = calloc(*count + 1, sizeof(*definition));
if (definition == NULL)
{
printf("allocation failed");
return NULL;
}
return definition;
}
int main()
{
unsigned int indexCount, i;
char ***dptr = GetIndexes(&indexCount);
if (dptr == NULL)
{
printf("memory Allocation failed");
}
for (i = 0; i < indexCount; i++)
{
unsigned int definitionsCount;
printf("Word number %u\n", i + 1);
dptr[i] = GetDefinitions(&definitionsCount);
if (dptr[i] != NULL)
{
/* use dptr[i] here or maybe somewhere else, but when you finish */
free(dptr[i]);
}
}
printf("%p", dptr);
/* now if you are done using dptr */
free(dptr);
return 0;
}
As already mentioned in the comment this is a very bad idea and just using double pointers is good here. But the below fixes should be done if you want to use pointers to allocate memory
index = calloc(n, sizeof(char));
should be
index = calloc(n, sizeof(char **));
and
definition = calloc(n+1, sizeof(char));
should be
definition = calloc(n+1, sizeof(char *));
I use this code, with this structure, im trying to make function to add item into array of this structure
typedef struct goods{
char *name;
int num;
} goods;
void addWord(char *what, goods *where, int pnr, int *arrsize, int n){
if (pnr >= *arrsize){
where = (goods*)realloc(where,*arrsize*2*sizeof(goods*));
*arrsize*=2;
}
where[pnr].name = (char*)malloc(strlen(what)*sizeof(char));
strcpy(where[pnr].name,what);
where[pnr].num = n;
}
in main function i have this:
int extstore = 1;
goods *store = (goods*)malloc(1*sizeof(goods*));
addWord(line, store, nr, &extstore, n);
Why am I getting an "invalid next size" runtime-error on the line where = (goods*)realloc(where,*arrsize*2*sizeof(goods*)); in addWord()?
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct goods{
char *name;
int r;
} goods;
int main()
{
int linelen, i, nr = 0, current_r;
char *line = NULL;
size_t len = 0;
int extstore = 1;
goods *store;
store = malloc(extstore*sizeof(goods*));
while (1){
while ((linelen = getline(&line, &len, stdin)) != -1){
if (line[linelen - 1] == '\n'){
line[linelen - 1] = '\0';
}
linelen = strlen(line);
if (line[0] == '#'){
if (sscanf(line,"#%d",¤t_r) != 1){
printf("bad input.");
return 0;
} else continue;
}
if (nr >= extstore){
store = realloc(store,extstore * sizeof(goods*) * 2);
extstore*=2;
}
store[nr].name = malloc(strlen(line)*sizeof(char));
strcpy(store[nr].name,line);
store[nr].r = current_r;
nr++;
}
if (linelen == -1) break;
}
printf("\n");
for (i = 0;i < nr;i++){
printf("%s, [id:%d]\n", store[i].name, store[i].r);
}
return 0;
}
extstore * sizeof(goods*) * 2
should be extstore * sizeof(goods) * 2 because the space for structures should be allocated - not just for pointers.
There is a fundamental problem in your code. You are passing pointer by value, which means that any change made to a pointer (not the variable pointed to, but the pointer itself) will not be visible from outside the function. You should pass a pointer by pointer instead, and you should check the result returned from realloc. Secondly, don't assign result of realloc back to same pointer - in case of failure you will lost pointer to memory -> thus, memory leak will occur.
To pass pointer by pointer:
void addWord( char *what, goods **where, size, ...) {
if ( *where == NULL) return; // nothing to do
if ( size < 1) return; // it would result in realloc=free call
goods *res = NULL;
res = realloc( *where, size * sizeof( goods));
if ( res != NULL) {
*where = res;
}
else {
// Error (re)allocating memory
// If realloc() fails the original block is left untouched,
// it is not freed or moved, so here *where is unchanged
}
And there is no need in C to cast a result from malloc.
* Error in `path': realloc(): invalid next size: 0x0000000000ec8010 *
This failure must be because "where" is invalid due to a heap corruption earlier in the execution.
C is pass-by-value.
Which means changing an argument in the function does not change the expression it was initialized from.
Thus, the first time realloc moves the memory, the pointer in main will be bad.
To correct that, either use an extra level of indirection, or preferably return the new value as the result.
(Anyway, you should check for allocation failure (malloc and realloc),
and you should not cast from void* to any pointer-type in C.)