Here's the code I am working with...
while(temp[i]!=0){
while(temp[i]!=3){
FrameBuffer[a]=temp[i];
i++;
a++;
}
FrameBuffer[a]=temp[i];
printf(" Framebuffer: %s ", FrameBuffer);
result=layer1(FrameBuffer,PacketAction);
i++;
a=0;
}
The problem is that I want FrameBuffer to be reset each time it goes through the inner while loop (Size of FrameBuffer is 0 at start of loop). I've tried using free(FrameBuffer) but I get an error because I free the array more than once. I also tried writing FrameBuffer=NULL, but that did not work. Any help would be greatly appreciated. Thank you!
If you just need to initialise FrameBuffer before the start of each inner loop, memset can be used-:
while(temp[i]!=0) {
memset(FrameBuffer, 0, sizeof(FrameBuffer));
while(temp[i]!=3) {
Since you don't show the declarations or give a particularly good description of the input string, temp, it is a bit hard to know what you're up to.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
extern int somefunc(const char *fb, int pa);
extern int layer1(const char *fb, int pa);
int somefunc(const char *temp, int PacketAction)
{
int rc = 0;
char *FrameBuffer = calloc(2048, sizeof(char));
if (FrameBuffer != 0)
{
int i = 0;
while (temp[i] != '\0')
{
int a = 0;
while (temp[i] != 3)
FrameBuffer[a++] = temp[i++];
FrameBuffer[a++] = temp[i++];
FrameBuffer[a] = '\0';
assert(a < 2048);
printf("Framebuffer: %.*s\n", a, FrameBuffer);
int result = layer1(FrameBuffer, PacketAction);
if (rc == 0)
rc = result;
}
}
return rc;
}
This is probably sufficient. The function layer1 gets a null terminated string in FrameBuffer (it has no other visible way of determining how long the data is).
Note that by declaring a in the scope of the outer loop, I don't need to reinitialize it at the end of the loop. I've used a++ and i++ to increment the counters; it allows for compact notation with no loss of readability to the experienced C programmer — though I concede it can be a little more difficult for novice programmers to handle. Nevertheless, the idiom is worth learning.
I wonder if the inner loop should check for '\0' as well as 3 (aka '\3' or '\003'); I would need to know whether nulls can ever appear in temp other than at the very end. The code shown takes a lazy way out of validating for no overflow of the FrameBuffer. It would be better still if the function was told the length of the input temp:
void somefunc(const char *temp, size_t templen, int PacketAction)
The code could be written more resiliently. It could probably use strlen(temp), but it isn't absolutely clear from the available information.
Related
I am practicing C language.
I wanted to use dynamic allocation to use only the size of the string I input as memory and check whether the input string was properly saved.
So, I wrote the following code using malloc and realloc functions.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void str_copy(char* str_array_f) {
void* tmp;
char buf;
unsigned char arr_size = 1;
unsigned char arr_cur = 0;
while ((buf = getchar())) {
if (buf == '\n') {
break;
}
str_array_f[arr_cur++] = (char)buf;
tmp = realloc(str_array_f, ((arr_size++) * sizeof(char)) + sizeof(char));
if (tmp != 0) {
str_array_f = tmp;
}
else {
printf("memory leak error occur! \n");
break;
}
}
str_array_f[arr_size - 1] = 0x00;
}
void main() {
int contiune = 1;
while (contiune) {
char* str_array = malloc(sizeof(char) + sizeof(char));
printf("Please type something : ");
str_copy(str_array);
printf("'str_array' have this : %s \n", str_array);
printf("-------------------------------------------------\n");
if (str_array[0] == '1') {
contiune = 0;
}
free(str_array);
}
}
And, as a result of the performance,
The following problems have occurred.
Strange values sometimes appear from the 5th character of the intermittently printed value
(To reproduce this issue, it is recommended to remove the while loop and try repeatedly)
In the case of repeatedly receiving a value by using the while loop, an error occurs after 4 repetitions.
If the allocated memory of tmp, which is a void type pointer, is released after line 22(e.g., 'free(tmp);'), when executed, no output and an error occurs immediately.
For the above 3 problems, I am not sure what is the cause and how to fix it.
Please let me know if there is a solution.
And, if there is a bad coding method in my code in terms of efficiency or various aspects, I would appreciate it if you let me know.
*Programming execution environment : Visual studio 2019
to explain what you're doing wrong I'm going to use a minimal example here
void change_x(int x) {
x = 2;
}
int main() {
int x = 1;
change_x(x);
printf("%i\n", x); // it'll print 1 not 2
return 0;
}
here the integer x is copied when the function is called and changing it won't really change the x in main. similarly you are doing in your code that str_array_f = tmp; it really won't change the str_array but the copied value. and you're trying to free a pointer that was reallocated before.
the fix for the example above is not to pass the value x instead pass the address of x (which is equivalent to pass by reference in other languages)
void change_x(int* x) {
*x = 2;
}
int main() {
int x = 1;
change_x(&x);
printf("%i\n", x); // it'll print 1 not 2
return 0;
}
and for your code
void str_copy(char** str_array_f) {...} // change the parameter
*str_array_f = tmp; // de reference and use it.
str_copy(&str_array); // call with it's address
And one more thing, don't reallocate more often it's not efficient. instead just just allocate your "array" type with a minimum size and when it's filled reallocate it with the size of 2 times of it (or 1.5 if you like)
I'm trying to code my own Turing machine. My program takes two files as arguments: my initial tape the machine will have to work with, and a rule file. This rule file consists in one rule per line, and each rule is five integers: current state, symbol found, new symbol, direction for the head to go, and new state. For that, I have a function that reads my file and puts each set of five ints found in a rule structure. An array of these structures is then generated.
What I'm trying to do is to return this array in order to be able to use it later on. Here is what I have :
struct rule {
int cur_state;
int symbol;
int new_symbol;
int direction;
int new_state;
};
typedef struct rule rule;
struct vect {
int nb_elem;
rule *p;
};
vect rule_generator (char * file_rule){
int line_number = 0;
int ligne;
char tmp;
rule rule_list[line_number];
vect output_rules;
FILE * file;
file = fopen(file_rule, "r");
for(tmp = getc(file); tmp != EOF; tmp = getc(file)){
if ( tmp == '\n')
line_number++;
}
output_rules.p = malloc(line_number*sizeof(rule));
assert(output_rules.p);
output_rules.nb_elem = line_number;
for (ligne = 0; ligne < line_number; ligne++ ){
fscanf(file, "%d %d %d %d %d", &rule_list[ligne].cur_state,
&rule_list[ligne].symbol, &rule_list[ligne].new_symbol,
&rule_list[ligne].direction, &rule_list[ligne].new_state);
}
fclose(file);
return output_rules;
}
int main (int argc, char *argv[]){
vect rule_list = rule_generator(argv[2]);
printf("symbole : %ls \n", &rule_list.p[0].symbol);
return 0;
}
As some of you may already have guessed, this doesn't print anything... I've been scratching my head for a while, trying to access my array. I could really use a hand here!
Few problems here.
You are declaring array with size 0.
int line_number = 0;
rule rule_list[line_number];
You don't need rule_list just remove it.
output_rules is no where being initilized other than memory allocating.
Solution:
I would suggest you to use output_rules for fscanf.
for (ligne = 0; ligne < line_number; ligne++ ){
fscanf(file, "%d %d %d %d %d", &output_rules.p[ligne].cur_state,
&output_rules.p[ligne].symbol, &output_rules.p[ligne].new_symbol,
&output_rules.p[ligne].direction, &output_rules.p[ligne].new_state);
}
Also did you mean to print the value of symbol?
As you are using %ls which is used to wchar_t *.
printf("symbole : %ls \n", &rule_list.p[0].symbol);
should be
printf("symbole : %d \n", rule_list.p[0].symbol);
There's lots going on here.
The main problem seems to be that this loop:
for(tmp = getc(file); tmp != EOF; tmp = getc(file)){
if ( tmp == '\n')
line_number++;
}
is going right the way through the file to the end, which means there's nothing left for fscanf() to read. If you want to read the whole file through once to find out the number of lines, and then read it again to read the content, you're going to have to either a) close and reopen it, or b) use the rewind() or fseek() function to go back to the start of the file.
(To be honest, an even better solution would be to design your code so that you don't need to read the file twice over. If you end up trying this and get stuck, ask again with a new question on this site.)
In addition, you should add these lines at the beginning of your code:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
to read in the header files which define the functions you're using, and put this line after your struct vect definition to define the type:
typedef struct vect vect;
Also, please run your compiler with warnings enabled. This would have helped you find some of these problems yourself!
gets doesn't work in the function neuePerson,
it worked when it was in a for loop, but then I changed it and now the compiler says isn't undefined.
I tried it with fgets, now there is no warning, but it still ignores fgets, so I cant write anything in the console.
in the main function's gets works. I'm a little bit confused... :o
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "readline.h"
//typedef struct Person {
// char name[50];
// char unit;
// int number;
//} Person;
typedef struct person {
char name[50];
char unit;
int number;
struct person *next;
} Person;
void neuePerson(Person *firstPerson) {
time_t t;
time(&t);
srand((unsigned int)t);
while (firstPerson->next != 0)
firstPerson = firstPerson->next;
printf("Gib einen Namen ein \n");
fgets(firstPerson->name, 50, stdin);
firstPerson->number = rand() % 99 + 1;
firstPerson->unit = rand() % 3 + 65;
firstPerson->next = (Person*)malloc(sizeof(Person));
firstPerson = firstPerson->next;
firstPerson->next = 0;
}
void ausgabe(Person *anfang) {
while (anfang->next != 0) {
printf("Name: %s", anfang->name);
printf(" Abteilung: %c", anfang->unit);
printf(" Tel.Nummer: %i\n", anfang->number);
anfang = anfang->next;
}
}
int main() {
Person* pers1 = (Person*)malloc(sizeof(Person));
//Person* test = (Person*)malloc(sizeof(Person));
//gets(test->name, 50);
//printf("%s", test->name);
pers1->next = 0;
char z = 'n';
while (z != 'e') {
printf("[n]eue Person, [a]usgabe, [e]nde");
z = getchar();
if (z == 'n') neuePerson(pers1);
else if (z == 'a') ausgabe(pers1);
}
}
The problem comes from the line buffering of standard input:
You read the option in main with getchar(), but the byte is returned to your program after you type the enter key. Only the initial char from the line is returned, the rest stays in the stream.
When you subsequently read the person's name with fgets(), it returns an empty line because it gets the \n that is still in the stream. Contrary to popular belief, fflush(stdin) is not the solution because it has undefined behavior. A better solution is to read the option this way:
int main() {
Person *pers1 = (Person*)malloc(sizeof(Person));
pers1->next = NULL;
pers1->unit = 0;
pers1->name[0] = '\0';
for (;;) {
int z, c;
printf("[n]eue Person, [a]usgabe, [e]nde ");
z = c = getchar();
while (c != EOF && c != '\n')
c = getchar();
if (z == EOF || z == 'e')
break;
else
if (z == 'n')
neuePerson(pers1);
else
if (z == 'a')
ausgabe(pers1);
}
}
You should improve your list handling: an empty list should be just NULL, it is incorrect to keep a dummy uninitialized structure pending at the end of the list. You can handle the update to the list head by passing a pointer to the head to neuePerson.
I agree with chqrlie's answer; in addition, don't forget to free up your list at after you exit the main while loop:
int main()
{
/** your While loop */
Person *nextp = pers1;
do {
free(nextp);
nextp = nextp->next;
} while (nextp != NULL);
}
It would be a good idea to separate the linked-list logic from everything else. You'll be glad you did now and when your program becomes larger.
Also, Become friends with valgrind.
First, since you asked about both gets and fgets, that enables me to quote from the man page :
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
I am going to take the liberty of re-writing your code to the minimal set, before I answer your question. You're testing gets, so I can remove everything afterward, and everything in your code that isn't called before gets. I'll also move your call to fgets from neuePerson to main. I'll also avoid heap memory to simply further, I trust you to figure out how to use the heap properly. Finally, I really don't like using uninitialized structs or main routines that don't have exit codes, so I'll do that as well. That looks like this :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "readline.h"
typedef struct person{
char name[50];
char unit;
int number;
struct person* next;
} Person;
int main() {
Person _pers1, *pers1 = &_pers1;
char z = 'n';
memset(pers1, 0, sizeof(Person));
while (z != 'e') {
z = getchar();
pers1->name = fgets(pers1->name, 50, stdin);
}
return 0;
}
At a high level, the problem is that you have two methods that handle strings in different ways. You've already been shown a solution that takes one of the methods - getchar - and makes it work like another method - fgets with a buffer size of 1 in this case. But there may well be many situations where you do not have enough information about both methods to do this. In this situation, for instance, if you did not know that newline characters were in the input feed at all, or you were programming in a language where fgets had a programmable stop rather than just stopping on a newline character, your original approach may have been more sensible.
So in this situation, when two methods aren't cooperating, it's often a good idea to use the same method throughout. That looks like this :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "readline.h"
typedef struct person{
char name[50];
char unit;
int number;
struct person* next;
} Person;
int main() {
Person _pers1, *pers1 = &_pers1;
char z[50];
memset(pers1, 0, sizeof(Person));
memset(z, 0, sizeof(char) * 50);
while (z[0] != 'e') {
fgets(z, 50, stdin);
fgets(pers1->name, 50, stdin);
}
return 0;
}
Making z 50 bytes big is of course overkill. I did this to illustrate a principle. If you use the same method the same way everywhere, you won't run into problems. You don't need to ask questions like "wait does z need to be 1 or 2 bytes? Should I call fgets with 2 or 1?". You already know "50 is the most I'll allow input to be". You can come back and optimize later, if there ends up being a reason to optimize.
I also want to mention, it's true that this line,
while (z[0] != 'e') {
has some flaws. It would be more correct to look at values other than 'e' . I'd recommend 0, EOF, '\n', and '\r'. But the only one of those you could have known about in advance is 0, since you set that. It would be best, in my opinion, to discover that the others needed to be added through testing and using your code, rather than to "kitchen sink" your code to avoid problems before they happen.
I am trying to read multiple lines from stdin, in which even lines are strings and odd lines are numbers separated by spaces. I'm trying to read the numbers as integers and the strings as... strings. It's part of a school project but it's not the entire thing; I managed the rest of the stuff but I can't manage to actually GET the strings and ints from stdin.
I add every name to experiments when i is even (I try to use it as a line number)
I tried using malloc to append a string n and store it as an int in a a 2d array data when I encounter a space, using int a to navigate through the line.
And then the printing part is just to try to show it works and.. it doesn't. I'm not busting any array's length and I felt like I watched out for malloc but I spent more than 15 hours on this part and nothing good is coming out of it. I wondered if someone could give me a hint.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char *experiments[100];
int data[10][20];
char name[101];
int i=0;
int j=0;
char *n;
char *g;
fgets(name, 100, stdin);
while ((strstr(name,"*** END ***")!=0)&&(name!=NULL)){
if((i%2)==0){
experiments[i/2]=name;
name[0]='\0';
}
else {
int a = 0;
while ((name[a]!='\n')&&(a<100)){
if (name[a]!=' '){
size_t len = strlen(n);
g = malloc(len + 1 + 1);
strcpy(g,n);
g[strlen(n)-2] = name[a];
g[strlen(n)-1] = '\0';
n[0]='\0';
*n = *g;
free( g );
a+=1;
}
else {
data[j][i]=*n;
j+=1;
n[0]='\0';
a+=1;
}
}
}
i+=1;
fgets(name,100, stdin );
}
int k=0;
for(k=0;k<=i;k+=1){
printf("printing\n");
printf("%s\n", experiments[k]);
if (experiments[k][0]=='\0') {
printf("oh shoot!");
}
}
return(0);}
You seem to have fundamental confusions regarding:
Do you know the saying "Give me six hours to chop down a tree and I will spend the first four sharpening the axe"? There are many problems here, and they're probably caused by a blunt axe. Whatever book you're using to learn C is failing to teach you. I recommend K&R 2E. Don't forget to do the exercises.
Yuck! Neither for nor return are functions! Please, for the love of life, if you want other people to read your code, make it presentable for them! It would help if your code were consistently indented, too.
Arrays (e.g. it's impossible for name!=NULL to evaluate false, so that expression is pointless), pointers and the implicit conversion from array to pointer that occurs in experiments[i/2]=name;. To clarify, every time you assign like that, the different elements will point to the same place, and the values stored within that place will be overwritten when you next call fgets.
malloc; you've used it in the wrong place, and the way you used it reinvents automatic storage duration (that is, all of your variables). You might as well just not use it at all.
fgets; its mode of failure leads to horrible crashes in your program.
Strings; see above.
Start by reading K&R 2E and doing the exercises as I mentioned earlier... Once you've completed that book I reckon you'll have a fine chance at filling in the blanks for this program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char *experiments[100] = { 0 };
int data[10][20] = { 0 };
char name[101] = { 0 };
size_t i = 0, j = 0;
fgets(name, sizeof name, stdin);
while (strstr(name,"*** END ***") != 0){
if(i%2 == 0){
experiments[i / 2] = malloc(strlen(name) + 1);
if (experiments[i / 2] == NULL) {
puts("OOPS! malloc failure!");
return 0;
}
strcpy(experiments[i / 2], name);
}
else {
/* XXX: I have no idea what any of this was meant to do *
* ... but it was all HORRIBLY WRONG so I removed it. *
* Try again once you've read K&R 2E and done the *
* exercises... */
}
i++;
fgets(name, sizeof name, stdin);
}
for (size_t k = 0; k < i / 2; k++){
puts("Printing...");
puts(experiments[k]);
if (experiments[k][0] == '\0') {
puts("oh shoot!");
}
free(experiments[k]);
}
return 0;
}
I cant figure out where I am messing up. I am passing an array of character pointers. Inside the function I am trying to use strtok to break up a string into smaller pieces to be assigned to the char * array. I can try printing it off in the function and it all shows up correctly. As soon as I try to print it back in main I just get garbage.
#include <stdio.h>
#include <string.h>
#define CMDLEN 100
#define MAXARG 5
void prompt();
int getCommand (char* cmdAndParameters[]);
int main() {
int numArgs = 0;
char* cmdAndParameters [MAXARG];
while (true){
prompt ();
numArgs = getCommand (cmdAndParameters);
}
}
void prompt() {
printf("shell> ");
}
int getCommand(char* cmdAndParameters[]){
int argNum = 0;
bool foundArg = true;
char* delimiters = " \t\n";
char userRequest[CMDLEN];
fgets(userRequest,sizeof(userRequest), stdin);
if ((cmdAndParameters[argNum] = strtok(userRequest, delimiters)) != NULL)
{
argNum++;
for (; argNum < MAXARG && foundArg; argNum++) {
if ((cmdAndParameters[argNum] = strtok(NULL,delimiters))
== NULL)
{
foundArg = false;
}
// merely to test output remove later
else {printf("%s\n", cmdAndParameters[argNum]);}
}
}
return argNum;
}
In this case, your inner array of chars is allocated "automatic", which is to say, on the stack. When you do the strtok, you're assigning a pointer to memory allocated on the stack, and then returning -- which means the memory is no longer allocated.
Move the userRequest array into file scope (ie, outside a block) or make the allocation 'static' and you'll have a better shot.
Update
Well, it's a little more than that, now that I look again.
First of all, you can clean it up considerably if you use a while loop, something like
argNum = 0;
while((cmdAndParameters[argNum++] = strtok(userRequest, delimiters)) != NULL)
; /* all the work is happening in the conditional part of the while */
or even a for loop as
for(argNum = 0;
(cmdAndParameters[argNum] = strtok(userRequest, delimiters)) != NULL);
argNum++)
; /* still all the work is in the for */
and now if argNum > 0 you know you found something.
Second, you need to think about how and when you're allocating memory. Your cmdAndParameters array is allocated when main starts (on the stack, it's "automatic") so it's around as long as your program, you're okay there. But your userRequest array is allocated auto in getCommand; when getCommand returns, the memory is deallocated; the stack pointer moves back over it and you have no guarantees any longer. So when you do the strtok, you're saving pointers into stack, which can lead to no good.
Do you want
for (; argNum < MAXARG && foundArg; argNum++)
or something like
for(argCntr = argNum; argCntr < MAXARG && foundArg; argCntr++)
Hope that helps.