I created a struct and a function that returns that struct.
Afterwards I'm calling that function twice, each time assigned to a different variable.
The problem is that the first variable changes after the second run.
What am I missing here?
code:
struct text_and_len {
char* text;
int len;
};
struct text_and_len get_text_and_length(){
int len;
scanf("%d ", &len);
char text[len];
fgets(text, len+1, stdin);
return (struct text_and_len) {text, len};
}
void get_input_and_check_is_within(){
struct text_and_len b = get_text_and_length();
printf("%s \n", b.text);
struct text_and_len a = get_text_and_length();
printf("%s \n", a.text);
printf("%s \n", b.text);
this will first print the b.text, but then will print the a.text twice.
These lines used in get_text_and_length()():
char text[len];
fgets(text, len+1, stdin);//over writes buffer by at least 1, 2 if wanting a C string. Will cause undefined behavior.(UB)
will potentially allow user to enter input that would over write the buffer.
The code as is also includes variables that reach end of life before they are needed else where, resulting in predictable, but unwanted behavior.
Also the member in the struct char* text; requires memory be allocated before being written to. Thus will also require freeing.
Below is your code refactored to address these, with some other modifications to the prototypes and calling methods that simplify the writing of the code...
struct text_and_len {
char* text;
int len;
};
void get_text_and_length(struct text_and_len *b){
printf("Enter max length of input string\n");
scanf("%d ", &(b->len));
//b->text[b->len];//VLA, but has already been declared as char *
b->text = malloc(b->len + 2);//room for NULL terminator AND newline
memset(b->text, 0, b->len+2);//zero variable to all NULL
//fgets(text, len+1, stdin);//text has no memory
//and as is would have over-written
//buffer - UB
printf("Enter string no longer than max length\n");
fgets(b->text, b->len+2, stdin);//note len+2 provides room
//for len char + NULL + newline
}
void get_input_and_check_is_within(struct text_and_len *b){
get_text_and_length(b);
printf("max length: %d \n", b->len);
printf("text entered:%s \n", b->text);
}
int main(void)
{
struct text_and_len a = {0};
get_input_and_check_is_within(&a);
free(a.text);//allocated in get_text_and_length()
return 0;
}
Related
I'm storing data in a struct and want to know why it's not being stored in the struct properly. I've check that the sscanf works properly by scanning it into variables instead and printing those. But as soon as I try to store it in this struct it doesn't work.
So I printed the struct and it shows Location, direction and name to be NULL as that's their default value and length is 0.
Ship *newShip = (Ship*)malloc(sizeof(Ship));
sscanf(line, "%s %s %d %[^\n]", newShip->location, newShip->direction,
&newShip->length, newShip->name);
printf("\nShip %d: \n\tLocation: %s \n\tDirection: %s \n\tLength: %d \n\tName: %s\n",
shipNum, newShip->location, newShip->direction, newShip->length, newShip->name);
shipNum++;
Edit The struct used follows:
typedef struct {
char *location;
char *direction;
int length;
char *name;
} Ship;
Edit: Example of string being formatted.
"D4 E 3 NullByte Sub"
Ship num was just a count I was using to track what ship number I was printing.
Any help would be great thanks.
Your pointers inside the struct is not pointing to a valid memory location which leads to undefined behavior.
Allocate memory for the struct members location,direction,name.
Eg:
Ship* newShip = malloc(sizeof(Ship));
newShip->location=malloc(size);
newShip->direction=malloc(size);
newShip->name=malloc(size);
size denotes the size of memory for each struct member.
Your structure contains pointers for the strings, not arrays. When you allocate it with malloc(), you must initialize these pointers to some allocate memory for sscanf() to store to. As posted, the code has undefined behavior. Furthermore, you should check for allocation failure and also verify the number of conversions returned by sscanf() to detect invalid input.
If your C library supports a common extension, the m allocation modifier, you could write this:
typedef struct {
char *location;
char *direction;
int length;
char *name;
} Ship;
Ship *create_ship(const char *line) {
Ship *newShip = calloc(sizeof(Ship), 1);
if (newShip) {
if (sscanf(line, "%ms %ms %d %m[^\n]", &newShip->location,
&newShip->direction, &newShip->length, &newShip->name) == 4)) {
printf("\nShip %d:\n\tLocation: %s\n\tDirection: %s\n"
"\tLength: %d\n\tName: %s\n", shipNum, newShip->location,
newShip->direction, newShip->length, newShip->name);
} else {
/* format error */
free(newShip->location);
free(newShip->direction);
free(newShip);
newShip = NULL;
}
}
return newShip;
}
For a simpler and more portable approach you could define the string fields in the Ship as arrays of char and use:
typedef struct {
char location[20];
char direction[4];
int length;
char name[50];
} Ship;
Ship *create_ship(const char *line) {
Ship *newShip = calloc(sizeof(Ship), 1);
if (newShip) {
if (sscanf(line, "%19s %3s %d %49[^\n]", newShip->location,
newShip->direction, &newShip->length, newShip->name) == 4)) {
printf("\nShip %d:\n\tLocation: %s\n\tDirection: %s\n"
"\tLength: %d\n\tName: %s\n", shipNum, newShip->location,
newShip->direction, newShip->length, newShip->name);
} else {
/* format error */
free(newShip);
newShip = NULL;
}
}
return newShip;
}
Writing a program in C and I am trying to pass two variables into the function kstrextend. Name which is a word or set of characters that is stored in the value kstring and a which is a numeric value, but name is not getting passed into the function at all as far as I can tell and I cannot figure out why. Is something not getting stored correctly? Because the function works just fine I just cannot get name passed in correctly.
Declaration of kstring and name:
kstring name;
char kstring[50];
Typedef:
typedef struct
{
char *data;
size_t length;
} kstring;
Function:
void kstrextend(kstring *strp, size_t nbytes)
{
char *nwData;
int lnth=strp->length;
if(lnth < nbytes)
{
// new array allocate with large size and copy data to new array
nwData = (char *)realloc(strp->data, nbytes);
// call abort in case of error
if(nwData == NULL)
{
abort();
}
//Making strp->data point to the new array
strp->data = nwData;
//Setting strp->length to the new size.
strp->length = nbytes;
for(int i = 0; i <= lnth; i++)
{
printf("\n %s",strp->data);
}
// filled with '\0' in remaining space of new array
for (int lp = lnth; lp < nbytes; lp++)
{
strp->data[lp] = '\0';
printf("\n %s", strp->data[lp]);
}
}
}
Portion of main:
size_t a;
char * k = kstring;
printf("\n Enter number: ");
scanf("%d", &a);
name.data = (char*)calloc(sizeof(k), 1);
strcpy(input, k);
name.length= kstring_length;
kstrextend(&name,a);
First of all, you have misleading variable name kstring. Use something else like kstring_init and assign it a value. I assume you want to initialize the name variable of type kstring with something and then change its length. So this is what it is all about. Then define a constant of type char * and initialize length and data of your kstring with it. Then use realloc to extend the memory of the pointer with the input value a, not with the size of k. That does not make sense. Since the size of k is the size of the pointer, which is constant.
In your function: don't use int if you pass size_t. Use the same datatype where you do the same things.
In your loop from 0 to lnth, you output the same string lnth+1 times, which does not make sense. You probably want to output the characters of the string. So use %c and use an index into the character array and don't set <= lnth but < lnth as upper limit. Take care with data types if signed and unsigned!
Design hint: If you have a if block, that wraps all your code... invert the condition and just exit so that the code is after the if block.
Take care when you work with size_t and int, since int is signed and size_t is not, which can give problems in if statements.
Don't use abort but rather exit. You don't want your program to abort abnormally and core-dump.
A working version of your program is:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
char *data;
size_t length;
} kstring;
kstring name;
char *kstring_init = "blabla";
void kstrextend(kstring *strp, size_t nbytes)
{
char *nwData;
size_t lnth = strp->length;
if ((int) lnth >= (int) nbytes) {
printf("Error, size already larger than requested size.\n");
exit(-1);
}
// new array allocate with large size and copy data to new array
nwData = realloc(strp->data, sizeof(char) * (int) nbytes);
if(nwData == NULL)
{
printf("Error, realloc returned NULL\n");
exit(-1);
}
//Making strp->data point to the new array
strp->data = nwData;
//Setting strp->length to the new size.
strp->length = nbytes;
for(int i = 0; i < lnth; i++)
{
printf("\n %c", strp->data[i]);
}
// filled with '\0' in remaining space of new array
for (int lp = lnth; lp < (int) nbytes; lp++)
{
strp->data[lp] = '\0';
printf("\n %c", strp->data[lp]);
}
}
int main(void)
{
size_t a;
printf("\n Enter number: ");
scanf("%d", &a);
name.length = strlen(kstring_init) + 1;
printf("Length of string is: %d\n", name.length);
name.data = (char*)malloc(sizeof(char) * name.length);
strcpy(name.data, kstring_init);
printf("Old string: %s\n", name.data);
printf("You want to reallocate %d bytes\n", a);
kstrextend(&name, a);
return 0;
}
This is my first time posting question, and I did try to find solution, but, even if I did found it I didn't recognize it.
So, as the title says, the problem is in this triggered exception "Exception thrown at 0x0F26372D (ucrtbased.dll) in lab10.exe: 0xC0000005: Access violation reading location 0xCCCCCCC4.
If there is a handler for this exception, the program may be safely continued.", which happens when I step into line -> free(word).
This did happen to me a few times when I was learning malloc, but I overlooked it - thinking there was some other problem. But now I see that I'am doing something wrong.
The point of the program is - writing the struct "word". I need to input sentence and "cut" it into words, and then every word put in struct together with size of letters in the word and ordinal number of the word.
#include <stdio.h>
#include <string.h>
struct word {
char text_word[50];
unsigned sizee; //number of letters of the word
unsigned number; //ordinal number of the word
};
void cutting_sentence(struct word *p, char *sen) { //sen is sentence
int size_sen, i, j;
size_sen = strlen(sen) + 1; //size of sentence
p = (struct word*)malloc(size_sen * sizeof(struct word));
if (p == NULL) {
printf("\nNot enaugh memory!");
return 0;
}
strcpy(p[0].text_word, strtok(sen, " ,.!?"));
p[0].sizee = strlen(p[0].text_word);
p[0].number = 1;
printf("word:%s \t size:%u \t ordinal number of the word:%u\n",
p[0].text_word, p[0].sizee, p[0].number);
for (i = p[0].sizee - 1, j = 1;i < size_sen;++i) {
if (*(sen + i) == ' ' || *(sen + i) == '.' || *(sen + i) == ','
|| *(sen + i) == '?' || *(sen + i) == '!') {
strcpy(p[j].text_word, strtok(NULL, " ,.!?"));
p[j].sizee = strlen(p[j].text_word);
p[j].number = j + 1;
printf("word:%s \t size:%u \t ordinal number of the
word:%u\n", p[j].text_word, p[j].sizee, p[j].number);
j++;
}
}
}
int main() {
char sentence[1024];
struct word *word;
printf("Sentence: ");
gets(sentence);
cutting_sentence(&word, sentence);
free(word); //here is exception triggered
return 0;
}
You're changing the local value of the pointer argument passed, you need to change the memory at its target for the caller to discover the location of the allocated memory. Since you didn't do that, you're trying to free the local variable word which is stored on the stack of main().
First thing to fix is not to have a variable identical to the name of a type, that's just evil.
Then change the function prototype to pass a double pointer:
void cutting_sentence(struct word **p, char *sen);
And remember that where you were using p you now need to use *p or first assign a local (word *) with the address value contained there.
void cutting_sentence(struct word **p, char *sen) { //sen is sentence
int size_sen, i, j;
size_sen = strlen(sen) + 1; //size of sentence
*p = (struct word*)malloc(size_sen * sizeof(struct word));
if (*p == NULL) {
printf("\nNot enaugh memory!");
return; //void cannot return a value
}
and so on changing every usage of p to *p.
and then
int main() {
char sentence[1024];
struct word *words;
printf("Sentence: ");
gets(sentence);
cutting_sentence(&words, sentence);
if (words != NULL)
free(words); //now valid
return 0;
}
There are a few more issues than those previously discussed.
[As already pointed out] your first argument should be struct word **. But, a simpler way is to eliminate it and change the return type to struct word *. This allows the code within the function to be simpler (i.e. no double dereferencing of a pointer)
Although allocating as many word structs as there are characters in the input string will work, that is somewhat unusual.
A better way [more idiomatic, at least] to do this is to use realloc inside the loop.
In either case, the array size can be trimmed to only use what it needs via a final realloc.
I think that your loop that scans sen looking for delimiters is overly complex. Simply using strtok in the loop will give the same effect with less complexity.
Also, you're not conveying back a count of the number of word. One way is to add an extra element to the array that has a size of zero (e.g. an end-of-list marker)
Here's is a refactored version that should help:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct word {
char text_word[50];
unsigned sizee; // number of letters of the word
unsigned number; // ordinal number of the word
};
struct word *
cutting_sentence(char *sen)
{ // sen is sentence
int curcnt = 0;
int maxcnt = 0;
char *token;
struct word *word;
struct word *words;
while (1) {
token = strtok(sen," ,.!?\n");
if (token == NULL)
break;
sen = NULL;
if (curcnt >= maxcnt) {
maxcnt += 100;
words = realloc(words,sizeof(struct word) * (maxcnt + 1));
}
word = &words[curcnt];
strcpy(word->text_word,token);
word->number = curcnt;
word->sizee = strlen(token);
++curcnt;
}
words = realloc(words,sizeof(struct word) * (curcnt + 1));
// set end-of-list
word = &words[curcnt];
word->sizee = 0;
return words;
}
int
main()
{
char sentence[1024];
struct word *words;
struct word *word;
printf("Sentence: ");
fflush(stdout);
fgets(sentence,sizeof(sentence),stdin);
words = cutting_sentence(sentence);
for (word = words; word->sizee != 0; ++word)
printf("main: number=%u sizee=%u text_word='%s'\n",
word->number,word->sizee,word->text_word);
free(words);
return 0;
}
the following proposed code:
eliminates redundant code
properly checks for errors
properly outputs error message (and the text reason the system thinks an error occurred to stderr
performs the desired functionality
properly initializes the struct word pointer
properly updates the struct word pointer
changed int sizee to size_t sizee because the function: strlen() returns a size_t, not an int
changed int i to unsigned i because the declaration of the struct field number is declared as unsigned
documents why each header file is included
allocates an instance of the struct word for every character in the sentence This is 'overkill'. The most possible amount of words would be if every word was only a single character. So, immediately, the size of the allocated memory could be cut in half. A loop, counting the word separators would result in the correct amount of allocated memory. You could easily add that feature.
Note the way that the function: strtok() is used. I.E. initial call before loop, then following calls at end of loop
And now the proposed code:
#include <stdio.h> // printf(), fgets(), NULL
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), free()
#include <string.h> // strlen(), strtok()
struct word
{
char text_word[50];
size_t sizee; //number of letters of the word
unsigned number; //ordinal number of the word
};
// notice the `**p` so can access the pointer in `main()` so it can be updated
void cutting_sentence(struct word **p, char *sen)
{ //sen is sentence
size_t size_sen = strlen(sen); //size of sentence
struct word *wordptr = *p;
wordptr = malloc(size_sen * sizeof(struct word));
if ( !wordptr )
{
perror("malloc failed");
exit( EXIT_FAILURE );
}
unsigned i = 0;
char * token = strtok(sen, " ,.!?");
while( token )
{
strcpy( wordptr[i].text_word, token );
wordptr[i].sizee = strlen( token );
wordptr[i].number = i;
printf("word:%s\t Length:%lu]tordinal number of the word:%u\n",
wordptr[i].text_word,
wordptr[i].sizee,
wordptr[i].number);
token = strtok( NULL, " ,.!?");
i++;
}
}
int main( void )
{
char sentence[1024];
struct word *wordArray = NULL;
printf("Sentence: ");
if( !fgets(sentence, sizeof( sentence ), stdin ) )
{
perror( "fgets failed" );
exit( EXIT_FAILURE );
}
// remove trailing new line
sentence[ strcspn( sentence, "\n") ] = '\0';
cutting_sentence(&wordArray, sentence);
free( wordArray ); //here is exception triggered
return 0;
}
A typical run of the code results in:
Sentence: hello my friend
word:hello Length:5 ordinal number of the word:0
word:my Length:2 ordinal number of the word:1
word:friend Length:6 ordinal number of the word:2
Notice that 'short' words result in an uneven output. You might want to correct that.
I'm new to C, so this may be a silly question to ask:
What I want to do here is to input the data to the array of pointers to a structure and then print it out. But I get a segmentation fault when running into the insert function.
Below is my code
common.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct book * Book;
struct book{
int id;
char *name;
};
extern int b_insert(Book *b, int id, char *name);
extern int b_print(Book books[], int len);
insert.c
#include "common.h"
int b_insert(Book *b, int id, char *name){
Book p;
p = (Book)malloc(sizeof(struct book));
p->id = id;
strcpy(p->name, name);
*b = p;
printf("success insert book:\n");
printf("\tID: %d Name: %s\n", (*b)->id, (*b)->name);
return 0;
}
int b_print(Book books[], int len){
int i;
printf("Book List\n");
for(i=0; i<len; i++){
printf("books[%d] = ID: %d, Name: %s\n", i, books[i]->id, books[i]->name);
}
return 0;
}
main.c
#include "common.h"
#define MAX 2
int main(){
Book books[MAX];
Book *b=books;
int i;
int id;
char name[10];
for(i=0; i<MAX; i++){
printf("please input new books info\n");
printf("ID: ");
scanf("%d", &id);
printf("Name: ");
scanf("%s", name);
if(b_insert(b, id, name) == -1){
printf("fail to insert\n");
}
b++;
}
b_print(books, MAX);
return 0;
}
Main problem:
Allocate memory for p->name before using
strcpy(p->name, name);
using malloc:
p->name = malloc(10); //Or some other size
Other problems:
Remove the cast here:
p = (Book)malloc(sizeof(struct book));
Why? Here is the answer
if(b_insert(b, id, name) == -1){ will never be true.
Check the result of malloc to check if it was successful in allocating memory.
Check the return value of all the scanfs to see if it was successful in scanning data.
Add a length modifier to the second scanf to prevent buffer overflows:
scanf("%9s", name); /* +1 for the NUL-terminator */
You're not allocating space for name:
int b_insert(Book *b, int id, char *name){
Book p;
p = malloc(sizeof(struct book));
if (p != NULL)
{
p->name = malloc(strlen(name)+1); // It allocates space where the input name will be copied.
if (p->name != NULL)
{
p->id = id;
strcpy(p->name, name);
*b = p;
printf("success insert book:\n");
printf("\tID: %d Name: %s\n", (*b)->id, (*b)->name);
}
else return -1; // No space to allocate string
}
else return -1; // No space to allocate struct
return 0;
}
As mentioned before, allocate space for p->name. You should probably also use something different to read the book title, either scanf format %ms with a pointer to a char pointer, or %9s with your buffer, otherwise the title "war or peace" will also result in a segfault.
Here you create a static variable and the space for it is allocated automatically.
Book p;
You can allocate a space manually when you assign it to pointer, in this line it's not pointer but static variable.
p = (Book)malloc(sizeof(struct book));
What's more if you want to refer to attribute of static variable you should use "." instead of "->". So you have two option. Create a pointer and allocate a space for the structure and then you "->" oraz create static variable.
p->id = id;
I am trying to dereference variables in a struct that is in a list, so here is my list and struct
struct packet {
unsigned short block_num;
unsigned short block_size;
unsigned short crc;
unsigned char *payload;
}packet;
/* Function and type declaration for list of packets */
typedef struct List{
struct packet *p;
struct List *next;
}List;
And here I am trying to do a toString():
char *tostring(List *h) {
char *str= malloc(STRSIZE);
char num[sizeof(List)*100];
str[0] = '\0';
while (h != NULL) {
sprintf(num, "package Number: %d \n", h->p->block_num);
sprintf(num, "block size: %d \n", h->p->block_size);
sprintf(num, "CRC: %d", h->p->crc);
strncat(str, num, STRSIZE - strlen(str) - 1);
h = h->next;
}
return str;
}
And I hit a segmentation fault, please help, thanks !
So, in C#, I will use list.ElementAt(i).block_num , how is it done in C ?
edit: new ones, the problem lies on my dereferencing
char *tostring(List *h) {
char *str= malloc(STRSIZE);
printf("line1");
char num[sizeof(List)*100];
char size[sizeof(List)*100];
char crcs[sizeof(List)*100];
char messages[sizeof(List)*100];
while (h != NULL) {
sprintf(num, "package Number: %d \n", h->p->block_num);
sprintf(size, "block size: %d \n", h->p->block_size);
sprintf(crcs, "CRC: %d", h->p->crc);
sprintf(messages, "CRC: %s", h->p->payload);
strncat(str,num,sizeof(num));
strncat(str,size,sizeof(size));
strncat(str,crcs,sizeof(crcs));
strncat(str,messages,strlen(num));
h = h->next;
}
return str;
}
Are you using sizeof(*h) to determine the number of List elements in an array?
sizeof(*h) returns the size of List. Since tostring() only get's a pointer to a List, it has no way of knowing how many elements are pointed to.
In any case, it appears you are then writing a string to a character array of this size. What does the size of List have to do with the number of elements in the array? What are you trying to do?
There are few things that may go wrong here
Your SRTSIZE may be low to hold all the text that you start appending to str. For that you can start with a big buffer for now to eliminiate that.
As posted from previous answers you are always overwriting num. You should write to 'str' after you create num every time
strncat implementation seems incorrect. You should use strlen(num).
strncat(str, num, strlen(num));
char * strncat ( char * destination, const char * source, size_t num );
The final parameter expects
Maximum number of characters to be appended.
refer : http://www.cplusplus.com/reference/cstring/strncat/