Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Edit: I am really sorry if I have wasted time of your guys, I was running out of time when posting this problem. Here comes the code that I have done my best to minimize it
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum Error {
ERROR_UNRESOLVED_NAME = 1,
ERROR_CANNOT_OPEN_FILE,
ERROR_NO_ARGV,
ERROR_UNRECOGNIZED_SYMBOL,
ERROR_UNCOMPLETED_SENTENCE,
ERROR_RECURSIVE_SELF
};
struct _Piece;
typedef struct _Piece *(*PieceFunc)(struct _Piece *, void *);
struct _Piece {
PieceFunc function;
void *backpack;
};
typedef struct _Piece Piece;
Piece *piece_create(PieceFunc func, void *pack) {
Piece *piece = malloc(sizeof(Piece));
piece->function = func;
piece->backpack = pack;
return piece;
}
typedef struct _Record {
char *name;
int name_len;
Piece *piece;
struct _Record *previous;
} Record;
Record *record_register(Record *pre, char *name, int name_len, Piece *piece) {
Record *record = malloc(sizeof(Record));
record->name = name;
record->name_len = name_len;
record->piece = piece;
record->previous = pre;
return record;
}
typedef struct {
char *file_name;
char *source;
int length;
int current;
int line;
int column;
} Source;
Source *source_create(char *s, int len, char *file_name) {
Source *source = malloc(sizeof(Source));
source->source = s;
source->file_name = file_name;
source->length = len;
source->current = 0;
source->line = source->column = 1;
return source;
}
Piece *apply(Piece *caller, Piece *callee) {
return caller->function(callee, caller->backpack);
}
// Part 3, internals
Piece *internal_self(Piece *callee, void *backpack) {
if (callee->function == internal_self) {
fprintf(stderr,
"recursive `self` calling between two pieces\n"
"piece 1 backpack: %p\n"
"piece 2: %p backpack: %p",
backpack, callee, callee->backpack);
exit(ERROR_RECURSIVE_SELF);
}
return apply(callee, piece_create(internal_self, backpack));
}
Piece *internal_put(Piece *callee, void *backpack) {
int *p_char = callee->backpack;
putchar(*p_char);
return piece_create(internal_self, NULL);
}
Source *main_create_source(char *file_name) {
FILE *source_file = fopen(file_name, "r");
if (!source_file) {
fprintf(stderr, "cannot open file \"%s\"\n", file_name);
exit(ERROR_CANNOT_OPEN_FILE);
}
char *source = NULL;
int length = 0;
while (true) {
char *line = NULL;
int line_len = 0;
line_len = (int)getline(&line, (size_t *)&line_len, source_file);
if (line_len < 0) {
break;
}
if (source == NULL) {
source = line;
} else {
source = realloc(source, sizeof(char) * (length + line_len + 1));
strcat(source, line);
// free(line);
}
length += line_len;
}
fclose(source_file);
return source_create(source, length, file_name);
}
#define MAIN_REGISTER_INTERNAL(record, name, func) \
record = record_register(record, name, sizeof(name) - 1, \
piece_create(func, NULL)); \
printf("%p %p\n", record, record->previous);
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "please specify source file by command line argument\n");
exit(ERROR_NO_ARGV);
}
Record *r = NULL;
MAIN_REGISTER_INTERNAL(r, "put", internal_put);
printf("main %p\n", r);
Source *s = main_create_source(argv[1]);
printf("main %p\n", r);
}
At first, the program crashed with a segmentation fault, I located the bad access code line, which have been deleted in this code demo. I figure out the original bug is that variable r in main would unexpected change after an unrelated calling to main_create_source, which would be demonstrated like this (save this code file as foo.c)
$ cc -O0 -g foo.c
$ ./a.out futaba_test.ftb
0x7fc0024025b0 0x0
main 0x7fc0024025b0
main 0x7fc0024025b0
$ cc -O3 -g foo.c
$ ./a.out futaba_test.ftb
0x7fe861c025b0 0x0
main 0x7fe861c025b0
main 0x7fe800000000
The behavior varied when changing optimization level. It has nothing todo with EOF since I have removed it, and in my opinion the memory for strcat's destination is rich enough. Thanks for any help.
By the way if there is any requirement to point out the purpose of this snippet. This is an interpreter for a minimal language I am working on. It is able to evaluate small source code snippet at the time and this is the first time I have tried to build it with -O3. The bug will only disappear without any level optimization.
(The following is the original post and is able to be ignored.)
I have this code file. When compiling with cc -O0 futaba.c, and running it with ./a.out futaba_test.ftb, the result will be
0x7fba60c025b0 0x0
0x7fba60c025e0 0x7fba60c025b0
0x7fba60c02610 0x7fba60c025e0
0x7fba60c02640 0x7fba60c02610
0x7fba60c02670 0x7fba60c02640
0x7fba60c026b0 0x7fba60c02670
0x7fba60c026d0 0x7fba60c026b0
0x7fba60c02700 0x7fba60c026d0
0x7fba60c02730 0x7fba60c02700
main 0x7fba60c02730
main 0x7fba60c02730
A%
(Zsh add the postfix %) everything is going well. But when compiling with -O3 rather than -O0, than result will be
0x7f8f274025b0 0x0
0x7f8f274025e0 0x7f8f274025b0
0x7f8f27402610 0x7f8f274025e0
0x7f8f27402640 0x7f8f27402610
0x7f8f27402670 0x7f8f27402640
0x7f8f274026b0 0x7f8f27402670
0x7f8f274026d0 0x7f8f274026b0
0x7f8f27402700 0x7f8f274026d0
0x7f8f27402730 0x7f8f27402700
main 0x7f8f27402730
main 0x7f8f00000000
[1] 27811 segmentation fault ./a.out futaba_test.ftb
The last two main line print different address, and the second one is not valid, which cause the stack overflow bug later in record_resolve function.
What is the problem?
That's a lot of code, but here's at least a flag:
char source_fetch(Source *s) {
return s->current == s->length ? EOF : s->source[s->current];
}
This forces EOF into a char, which is a very bad idea. That's why all standard C functions that can return EOF (like getchar() return int.
No idea what an optimizing compiler can make out of that, but once you factor in code that waits for EOF using that ... it's smelly.
Note: this is perhaps bad form as an answer; but it's pointing out a concrete problem with the code.
Also none of the heap allocations seems to have code looking for NULL being returned; that's a bit scary too.
Related
When using the auto completion with the Readline library in C, the prompt is reprinted when typing the tab key twice:
(prompt) view NAME_OF_F (user presses tab twice)
NAME_OF_FILE1 NAME_OF_FILE2 (suggestions by Readline)
(prompt) view NAME_OF_F
I'd like to suppress the reprinting of the prompt on the 3rd line by keeping the first line printed with the suggestions below it like such:
(prompt) view NAME_OF_F (user presses tab twice)
NAME_OF_FILE1 NAME_OF_FILE2 (suggestions by Readline)
I'd like the cursor back at the end of the first line that has the prompt.
Compiled with gcc -Wall -O0 -ggdb -fno-builtin rline.c -o rline -lreadline -ltermcap.
Here's a code sample:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <readline/readline.h>
int execute_line(char *line);
void initialize_readline();
static char **fileman_completion(char *text, int start, int end);
static char *command_generator(char *text, int state);
char *command[] = { "view", "quit", (char *)NULL };
int done; /* When non-zero, this global means the user is done using this program. */
int main(int argc, char **argv)
{
char *line;
initialize_readline(); /* Bind our completer. */
for ( ; done == 0; ) {
line = readline("> ");
if (!line)
break;
if (*line)
execute_line(line);
free(line);
}
return 0;
}
/* String to pass to system(). This is for the VIEW command. */
static char syscom[1024];
int execute_line(char *line)
{
int i = 0;
char *word;
/* Isolate the command word. */
while (line[i] && whitespace(line[i]))
i++;
word = line + i;
while (line[i] && !whitespace(line[i])) i++;
if (line[i]) line[i++] = '\0';
if (strcmp(word, "quit") == 0) {
done = 1;
return 0;
} else if (strcmp(word, "view")) {
fprintf(stderr, "%s: Choose only \"view FILE\" or \"quit\" as your command.\n", word);
return -1;
}
/* Get argument to command, if any. */
while (whitespace(line[i])) i++;
word = line + i;
if(!word || !*word) {
fprintf(stderr, "view: Argument required.\n");
return -1;
}
sprintf(syscom, "more %s", word);
return system(syscom);
}
void initialize_readline()
{
rl_readline_name = "rline";
rl_attempted_completion_function = (rl_completion_func_t *)fileman_completion;
}
static char **fileman_completion(char *text, int start, int end)
{
if (start == 0)
return rl_completion_matches(text, (rl_compentry_func_t *)*command_generator);
return NULL;
}
static char *command_generator(char *text, int state)
{
static int list_index, len;
char *name;
if (!state) {
list_index = 0;
len = strlen(text);
}
while ((name = command[list_index++]))
if (strncmp(name, text, len) == 0)
return strdup(name);
return NULL;
}
The program only accepts the commands view FILE_NAME to view the contents of a file and quit to exit the program.
The example is a shortened version of a sample program found here.
I don't think that readline has anything like that built in, but it does provide a lot of customisation possibilities if you want to try to write the logic yourself.
You could try writing a custom rl_completion_display_matches_hook to display the completion list. But it's not entirely clear to me how you would restore the cursor position afterwards. I don't think readline has a public interface for either finding or resetting the cursor position. (And, of course, it's possible that the completion list was so big that the original command scrolled off the screen.)
As an alternative, I was able use the hook to print the completion list over top of the current line and then redisplay the prompt after the completion list (although I cheated by assuming that the current input is always just one line). That's not quite what you asked for, but it may be useful for demonstration purposes. I used the following custom match printer:
static void display_matches(char** matches, int len, int max) {
putp(carriage_return);
putp(clr_eol);
putp(cursor_up);
rl_display_match_list(matches, len, max);
rl_forced_update_display();
}
I also added the following to the initialisation function:
rl_completion_display_matches_hook = display_matches;
setupterm(NULL, 1, (int*)0);
Thanks #rici for the inspiration. I got it working with his function with some modifications.
In order for this to work properly you need to download the readline library. In the rlprivate.h file from readline, I removed the lines char **lines;, and the line #include "realdine.h" from display.c. Then in your own .c you must have an #include </PATH/TO/display.c>. In that display.c, an #include points to the modified rlprivate.h. All of this so that I can have access to _rl_move_vert(1).
static void display_matches(char** matches, int len, int max)
{
int saved_point = rl_point;
char *saved_line = rl_copy_text(0, rl_end);
rl_save_prompt();
rl_replace_line("", 0); // Clear the previous text
putp(cursor_up);
_rl_move_vert(1);
rl_display_match_list(matches, len, max);
putp(cursor_up);
rl_restore_prompt();
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
putp(cursor_down);
free(saved_line);
}
I am trying to find the file(say marks.txt) in the particular path passed as argument to a function. Is it possible to give the filename and path as arguments to a function which checks if the file exists and prints out the path?
The below function only takes path as argument.
int fileexists(const char *path){
File *ptr = fopen(path, "r");
if (fptr == NULL)
return 0;
fclose(fptr);
return 1;
}
The required function prototype :
int fileexists(const char *path, const char *filename)
There are two parts to this question, and the right answers to them depend on what you're trying to do.
Concatenate a directory name and a file name to form a full path name.
Determine whether a file (referred to by a full path name) exists or not.
Concatenating a directory name and a file name is straightforward. Your friendsstrcpy and strcat will do most of the work. There are a few minor details to be careful of: (a) You'll need a big enough buffer for the full pathname, and you'll need to decide whether to use a fixed-size array (perhaps of size MAX_PATH), or a malloc'ed buffer; (b) you might need to insert an explicit '/' character (and it usually doesn't hurt to stick one in even if the directory string already ends in one); (c) under Windows you might want to use '\\' instead of '/'.
And then determining whether a file named by a full pathname exists is already well answered over at What's the best way to check if a file exists in C?. The big question to ask here is, are you asking whether the file exists in preparation to doing something with the file? If so, you have a serious vulnerability if you check for the file's existence, but then before you do the other thing, something else happens to cause the file to appear or disappear. So rather than checking-and-then-doing, it's usually better to just try doing the other thing, and deal gracefully with any errors.
The function you have checks if the file can be opened, but it will fail for some files that exist but you have no rights to open. I'd use stat instead. To concatenate the path and filename you can use string functions.
The usual Unix C APIs are dismal. It takes lots of effort to do the simplest of things correctly - and even then I'm not sure that I didn't forget some Unix-ism like signal handling or some obscure error cases. I.e. stuff that's rather trivial to get right in modern C++.
I wish someone designed a modern C system API and implemented it for at least Linux, so that our suffering would end...
Usually, string concatenation requires some higher level API to be done while maintaining a modicum of sanity. Thus, the example below uses a strbuilder class to build the string. This makes things vaguely readable and avoids most common mistakes.
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct strbuilder {
unsigned items, item;
size_t length, *lengths;
char *str, *dst;
};
bool strbuilder_pass(struct strbuilder *builder, int *rc);
void strcat_str(struct strbuilder *builder, const char *src);
void strcat_c_ifnone(struct strbuilder *builder, char c);
bool strbuilder_is_freed(const struct strbuilder *builder);
int fileExists(const char *path, const char *filename)
{
const char pathSep = '/';
int rc;
struct strbuilder bld = {0};
while (strbuilder_pass(&bld, &rc))
{
strcat_str(&bld, path);
strcat_c_ifnone(&bld, pathSep);
strcat_str(&bld, filename);
if (!rc)
{
struct stat statbuf;
printf("path = %s\n", bld.str);
rc = stat(bld.str, &statbuf);
}
}
assert(strbuilder_is_freed(&bld));
return rc;
}
int main()
{
int rc = fileExists("/", "dev");
assert(rc == 0);
return 0;
}
The string building is controlled by a strbuilder_pass function, which advances the string builder's state through five passes of operation:
Determine the number of items whose width has to be stored (avoids the need to call strlen twice).
Prepare the length storage vector. Determine the length of the buffer needed.
Prepare the output string buffer. Concatenate the elements into the buffer.
Use the output string buffer.
Free the output string buffer.
This API is not particularly special, but fits this use case. Some other ad-hoc approach would work too, but this is IMHO a bit more elegant.
void strbuilder_free(struct strbuilder *builder)
{
free(builder->lengths);
free(builder->str);
memset(builder, 0, sizeof(*builder));
}
bool strbuilder_pass(struct strbuilder *builder, int *rc)
{
if (!builder->length) {// start of pass 1
builder->length = 1; /*term*/
*rc = EAGAIN;
return true;
}
else if (!builder->lengths) // end of pass 1
{
builder->lengths = malloc(sizeof(*builder->lengths) * builder->items);
if (builder->lengths)
return true;
*rc = ENOMEM;
}
else if (!builder->str) // end of pass 2
{
builder->dst = (builder->str = malloc(builder->length));
builder->item = 0;
builder->length = 0;
if (builder->dst) {
*builder->dst = '\0';
return true;
}
*rc = ENOMEM;
}
else if (builder->dst) // end of pass 3
{
while (*builder->dst) { // include optional content
builder->dst++; // skip
builder->length++;
}
builder->dst = NULL;
*rc = 0;
return true;
}
else if (!builder->dst) // end of pass 4 (if any)
{}
else {
*rc = EINVAL;
}
strbuilder_free(builder);
return false;
}
void strcat_str(struct strbuilder *builder, const char *src)
{
if (!src)
return;
if (!builder->lengths) // pass 1
builder->items ++;
else if (!builder->str) // pass 2
{
size_t len = strlen(src);
builder->lengths[builder->item++] = len;
builder->length += len;
}
else if (builder->dst) // pass 3
{
size_t len = builder->lengths[builder->item++];
if (*builder->dst && (!len || *builder->dst != *src))
{
builder->dst++;
builder->length++;
}
memcpy(builder->dst, src, len);
builder->dst += len;
builder->length += len;
*builder->dst = '\0';
}
}
void strcat_c_ifnone(struct strbuilder *builder, char c)
{
if (!builder->lengths) {} // pass 1
else if (!builder->str) // pass 2
{
if (c) builder->length ++;
}
else if (builder->dst) // pass 3
{
if (!builder->length || builder->dst[-1] != c)
*(builder->dst) = c;
}
}
bool strbuilder_is_freed(const struct strbuilder *builder)
{
return !builder || (!builder->lengths && !builder->str);
}
You probably want something like this (no error checking for brevity):
...
#include <string.h> // for str* functions
#include <unistd.h> // for access
#include <stdlib.h> // for malloc
...
int fileexists(const char *path, const char *filename)
{
char *name= malloc(strlen(path) + strlen(filename) + 1);
strcpy(name, path);
strcat(name, filename);
int retval = access(name, F_OK) == 0;
free(name);
return retval;
}
Call like this:
if (fileexists("/some/path/", "somefilename.txt")) ...
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I've been trying to work with structures, pointers and memory in C.
I have created this structure
typedef struct {
int id;
char *name;
} Object;
here is constructor
void object_ctor(Object *o, int id, char *name)
{
o->id = id;
o->name = malloc(sizeof(name));
if(sizeof(o->name)!=sizeof(name))
{
o->name=NULL;
}
else
{
strcpy(o->name, name);
}
}
here is decleration of o1
char tmp_name[] = "Hello 1";
Object o1;
object_ctor(&o1, 1, tmp_name);
here is destructor
void object_dtor(Object *o)
{
if(o->name != NULL)
{
free(o->name);
o->name = NULL;
}
}
printing object
void print_object(Object *o)
{
printf("ID: %d, NAME: %s\n", o->id, o->name);
}
calling copy
Object copy;
print_object(object_cpy(©, &o1));
and I´m trying create a copy of one structure to another (I have already constructed them).
Object *object_cpy(Object *dst, Object *src)
{
if(src!=NULL)
{
const size_t len_str=strlen(src->name)+1;
dst->name = malloc(10000000);
dst->id = src->id;
strncpy (dst->name, src->name,len_str);
}
if (strcmp(dst->name,src->name)!=0)
{
dst->name = NULL;
}
return dst;
}
But then when I'm trying to free both copy and original src I get a segmentation fault. I've been trying to run it through gdb and it said that I'm freeing same memory twice so I assume that the code for copying is wrong, but I don't know where.
And here is code that gives me segmentation fault
printf("\nCOPY EMPTY\n");
object_dtor(©);
o1.id = -1;
free(o1.name);
o1.name = NULL;
object_cpy(©, &o1);
print_object(©);
print_object(&o1);
I´m including these libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
I'm using the std=c99 flag for to compile.
There is at least a problem here:
void object_ctor(Object *o, int id, char *name)
{
o->id = id;
o->name = malloc(sizeof(name));
if (sizeof(o->name) != sizeof(name))
{
o->name = NULL;
}
else
{
strcpy(o->name, name);
}
}
sizeof(name) is not the length of the string pointed by name. You need strlen(name) + 1 (+1 for the NUL terminator).
And your test if (sizeof(o->name) != sizeof(name)) is pointless, and I'm not sure what you're trying to achieve here.
You probably want this:
void object_ctor(Object *o, int id, char *name)
{
o->id = id;
o->name = malloc(strlen(name) + 1);
if (o->name != NULL)
strcpy(o->name, name);
}
There are similar problems in object_cpy:
pointless use of strncpy
pointless allocation of a 10Mb buffer
pointless test strcmp(dst->name, src->name)
You probably want this:
Object *object_cpy(Object *dst, Object *src)
{
if (src != NULL)
{
const size_t len_str = strlen(src->name) + 1;
dst->name = malloc(len_str);
if (dst->name != NULL)
{
dst->id = src->id;
strcpy(dst->name, src->name);
}
}
return dst;
}
With these corrections following code works fine:
int main()
{
char tmp_name[] = "Hello 1";
Object o1, copy;
object_ctor(&o1, 1, tmp_name);
object_cpy(©, &o1);
print_object(©);
print_object(&o1);
object_dtor(&o1);
object_dtor(©);
}
Event if this is not directly an answer to your problem, I'll give you how I organize my code in order to avoid memory problem like yours.
First, it all resolve around a structure.
To each structure, if needed, I do a "Constructor" and a "Destructor".
The purpose of the constructor is simply to set the structure in a coherent state. It can't never fail (implying that any code that could fail, like malloc, should not be in the constructor).
The purpose of the destructor is to clean the structure.
One little trick that I like to use is to put the constructor in a macro, allowing me to do something like 'Object var = OBJET_CONSTRUCTOR'.
Of course, it's not alway possible, it's up to you to be carreful.
For your code, it could be :
typedef struct {
int id;
char *name;
} Object;
#define OBJECT_CONSTRUCTOR {.id = -1,\ \\ Assuming -1 is relevant in your case, like an error code or a bad id value. Otherwise, it's useless.
.name = NULL}
void Object_Constructor(Object *self)
{
Object clean = OBJECT_CONSTRUCTOR;
*self = clean;
}
void Object_Destructor(Object *self)
{
free(self->name);
}
Here we go.
How to use it is simple : You always begin by the constructor, and you alway end by the destructor. That's why it's useless to set the char pointer "name" to NULL in the destructor, because it should not be used after by any other function that the constructor.
Now, you can have "initialisation" function. You can do a plain initialisation (it is your constructor function), or a copy initialisation, etc etc
Just keep in mind that the structure have been called into the constructor. If not, it's the developer fault and you do not have to take that in count.
A behavior that can be nice is, in case of error, to not modify the structure.
Either the structure is entierly modified in succes, or not at all.
For complex structure that can fail at many point, you can do that by "swapping" the result at the end.
void Object_Swap(Object *first, Object *second)
{
Object tmp = OBJECT_CONSTRUCTOR;
tmp = *fisrt;
*first = *second;
*second = tmp;
}
bool Object_InitByPlainList(Object *self, int id, consr char *name)
{
Object newly = OBJECT_CONSTRUCTOR;
bool returnFunction = false;
newly.id = id;
if (!(newly.name = strdup(name))) {
printf("error : %s : strdup(name) : name='%s', errno='%s'.\n", __func__, name, strerror(errno));
goto END_FUNCTION;
}
// Success !
Object_Swap(self, &newly);
returnFunction = true;
/* GOTO */END_FUNCTION:
Object_Destructor(&newly);
return (returnFunction);
}
It may be seem overcomplicated at the first glance, but that organization allow you to add more futur step "that can fail" cleanly.
Now, you can even do something this simply :
bool Object_InitByCopy(Object *dst, Object *src)
{
return (Object_InitByPlainList(dst, src->id, src->name));
}
All you have to do is to say in the documentation :
The first function to be called have to be "Object_Constructor"
After the "Object_Constructor", only the "Object_Init*" function can be called.
The last function to be call have to be "Object_Destructor"
That's all. You can add any "Object_*" function that you whant, like :
void Object_Print(const Object *self)
{
printf("ID: %d, NAME: %s\n", self->id, self->name);
}
Hope this organization will solve your memory problem.
An example :
int main(void)
{
Object test = OBJECT_CONSTRUCTOR;
Object copy = OBJECT_CONSTRUCTOR;
if (!Object_InitByPlainList(&test, 1, "Hello World !")) {
// The function itself has logged why it has fail, so no need to add error printf here
return (1);
}
Object_Print(&test);
if (!Object_Copy(©, &test)) {
return (1);
}
Object_Destructor(&test);
Object_Destructor(©);
return (0);
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Hello I got this warning with gcc(version 5.4.0) on a C11 program compiled with the following command:
$ gcc -g -Wall -std=c11 main.c -o minishell
main.c: In function ‘process_new’:
main.c:184:10: error: assignment of read-only variable ‘s’
s = slice_next(s, ':')) {
But nothing with clang (version 3.8.0):
$ clang -g -Wall -std=c11 main.c -o minishell # Compile without warning.
I am on Ubuntu 16.04.
Here is the code
// The loop that generate the warning with gcc.
for (str_slice s = slice_at(paths, ':');
!slice_empty(s);
s = slice_next(s, ':')) {
// ^ Gcc complains here.
const char *full_path = build_full_path(progname, s);
/* I use with full_path but nothing with s after this point. */
// There is no aliasing on full_path at this point.
free((void *)full_path); .
}
And here the definition of str_slice:
typedef struct _str_slice {
const char* data;
const uint32_t len; // end - data len of slice.
//^^^^^ Source of gcc warning.
} str_slice;
And the functions to use it:
inline
uint32_t slice_len(const str_slice slice) {
return slice.len;
}
inline
const char* slice_data(const str_slice s) {
return s.data;
}
inline
str_slice slice_new(const char* data, uint32_t len) {
return (str_slice) { data, len };
}
inline
str_slice slice_at(const char* data, const char c) {
const char* end = strchr(data, c);
return slice_new(data, end - data);
}
inline
str_slice slice_next(const str_slice s, const char c) {
const char* data = slice_data(s) + slice_len(s) + 1; // skip c
const char* end = strchr(data, c);
if (end != NULL) {
return slice_new(data, end - data);
} else {
return slice_new(NULL, 0);
}
}
inline
bool slice_empty(const str_slice s) {
return s.len == 0;
}
And if necessary the code about build_full_path
const char* build_full_path(const char* progname, const str_slice slice) {
size_t len_progname = strlen(progname);
// Save additional 2 bytes for adding '/' and '\0'.
size_t full_path_size = len_progname + slice.len + 2;
size_t malloc_size = sizeof(char) * full_path_size;
char *full_path = malloc(malloc_size);
full_path[full_path_size - 1] = '\0';
memcpy(full_path, slice.data, slice.len);
full_path[slice.len] = '/';
memcpy(full_path + slice.len + 1, progname, len_progname);
return (const char *) full_path;
}
When compile with clang I got an executable with the good behavior.
So I made something wrong? Or I found a bug?
Here the full code of my program(outdated): https://gist.github.com/darnuria/12af88c509310c2b40e0031522882720
Edit: Use of memcpy instead of strncpy. Remove of const on scalar types.
In the structure the data member len is declared as a constant data member.
typedef struct _str_slice {
const char* data;
const uint32_t len; // end - data len of slice.
^^^^^^
} str_slice;
It means that it can be changed and as result you may not assign one object of the structure to another object of the structure.
I just started programming in C for school. I am being asked to do a program that uses a FIFO struct to resolve math problems. I got the folowing code on the internet for a FIFO, I just don't know how to use it. I tried a lot of things and I can't find anything useful on the internet or maybe that I just don't know the right thing to research but could you please help me? Thanks!
#include <stdio.h>
#include <stdlib.h>
typedef struct pile
{
int donnee;
struct pile *precedent;
} Pile;
void pile_push(Pile **p_pile, int donnee)
{
Pile *p_nouveau = malloc(sizeof *p_nouveau);
if (p_nouveau != NULL)
{
p_nouveau->donnee = donnee;
p_nouveau->precedent = *p_pile;
*p_pile = p_nouveau;
}
}
int pile_pop(Pile **p_pile)
{
int ret = -1;
if (p_pile != NULL)
{
Pile *temporaire = (*p_pile)->precedent;
ret = (*p_pile)->donnee;
free(*p_pile), *p_pile = NULL;
*p_pile = temporaire;
}
return ret;
}
void pile_clear(Pile **p_pile)
{
while (*p_pile != NULL)
{
pile_pop(p_pile);
}
}
I tried doing this:
int main()
{
int return_val;
Pile pile;
pile_push(Pile, 5);
return_val = pile_pop(Pile);
printf(return_val);
}
and got this error:
expected expression before 'Pile'
too few arguments to function 'pile_push'
You have mixed up Pile and pile which is the issue with the first warning. The functions expect a pointer to a pointer to a Pile. That is: They update the value of a pointer, so they need to be passed a reference to a pointer. Your use of printf is also wrong.
int main()
{
int return_val;
Pile *pile = NULL;
pile_push(&pile,5);
return_val = pile_pop(&pile);
printf("return_val is: %d\n",return_val);
}