C structure; overcoming passing a string to a char - c

I am trying to print a simple structure, which does not work because I am trying to pass a string into a char (I know this is illegal). Yet I cannot figure out how to overcome this. I know there's a way with strcpy and without strcpy, how can I correct this? I have searched the forum and found similar questions, but was unable to apply them to my problem.
#include <stdio.h>
struct article
{
int number;
int quantity;
char description[21];
};
void print(struct article *p)
{
printf("Article Number: %d\nQuantity: %d\nDescription: %s", p->number, p->quantity, p->description);
}
int main()
{
struct article *mydata;
mydata->number = 333;
mydata->quantity = 465;
mydata->description = "Wall Street Journal\n";
print(mydata);
return 0;
}

struct article mydata = {
333,
465,
"Wall Street Journal\n"
};
print(&mydata);
struct article mydata;
mydata.number = 333;
mydata.quantity = 465;
strcpy(mydata.description, "Wall Street Journal\n");
print(&mydata);

First off, you are declaring a pointer to a struct article. You need to allocate memory for that pointer. It won't be allocated on the stack automatically for you. Using malloc you allocate dynamic memory to the heap.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
struct article *mydata = malloc(sizeof(struct article));
if(article == NULL) {
exit(1);
}
mydata->number = 333;
mydata->quantity = 465;
char *description = "Wall Street Journal\n";
size_t len = strlen(description);
memcpy(mydata->description, description, len);
mydata->description[len] = '\0';
print(mydata);
free(mydata);
return 0;
}

You can also do this. But why do you need alternative ways if you have a function that can do the job for you.
char mydescription[]="Wall Street Journal\n";
int count =0 ;
for( count =0 ; mydescription[count] != '\0' ; count++)
{
mydata->description[count] = mydescription[count] ;
}

Related

Most effective way to print the info of a entire structure C?

I want to know if there is a more effective way (less lines, less memory) to print the information contained in the string. I was thinking in a cycle with the funtion argument. For example if you need to print the info(name, group and birthdate) of 100 students, I guess there is a better way that write printstudent( studentn) a hundred times.
The thing is that I dont know how to create a cycle so calls from student1 to student100. I cannot call it student[i] or can I?.
I am open to any kind of suggestions or ideas Thanks!
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
void printstudents(struct st student);
struct st {
char familia[1000];
char imia[1000];
char otchestvo[1000];
int gruppa;
int grozhdenia;
};
int main() {
struct st student1;
struct st student2;
struct st student3;
//Информация студентов:
strcpy(student1.familia, "Putin");
strcpy(student1.imia, "Vladimir");
strcpy(student1.otchestvo, "Vladimirovich");
student1.gruppa = 40040;
student1.grozhdenia = 1952;
strcpy(student2.familia, "Gordon");
strcpy(student2.imia, "Dymitro");
strcpy(student2.otchestvo, "Aleksandrovich");
student2.gruppa = 50050;
student2.grozhdenia = 1953;
strcpy(student3.familia, "Emelianenko");
strcpy(student3.imia, "Fedor");
strcpy(student3.otchestvo, "Olegovich");
student3.gruppa = 60060;
student3.grozhdenia = 1950;
printstudents(student1);
printstudents(student2);
printstudents(student3);
return 0;
}
void printstudents(struct st student) {
printf("Student: %s %s %s, %d, %d \n", student.imia, student.otchestvo,
student.familia, student.gruppa, student.grozhdenia);
}
#include <stdio.h>
#include <string.h>
struct st;
void printstudents(const struct st *student);
struct st {
char familia[1000];
char imia[1000];
char otchestvo[1000];
int gruppa;
int grozhdenia;
};
int
main(void)
{
struct st student[3] = {
{ "Putin", "Vladimir", "Vladimirovich", 40040, 1952 },
{ "Gordon", "Dymitro", "Aleksandrovich", 50050, 1953 },
{ "Emelianenko", "Fedor", "Olegovich", 60060, 1950}
};
for( int i = 0; i < 3; i ++ ){
printstudents(student + i);
}
return 0;
}
void
printstudents(const struct st * student)
{
printf("Student: %s %s %s, %d, %d\n",
student->imia,
student->otchestvo,
student->familia,
student->gruppa,
student->grozhdenia
);
}
If we are talking actual performance in terms of execution speed and memory use, then here are the most obvious bottlenecks:
printf with its format string parsing is slow. It is likely quite a bit faster to use repeated puts calls than a single printf.
Obviously you shouldn't be passing your huge structs by value to the function. struct st student leads to a several kb large struct getting copied to the stack, in case your compiler fails to inline the function call. As a rule of thumb, never pass structs by value. Use pointers.
You make hard copies of constant string literals. You could have just used const char* familia and then do student2.familia = "Gordon"; which is much faster than strcpy. The down-side is that you only get read-only memory if you do like this.
Here's a reworking of your code to use a statically stack-allocated array of 3 student structures (and a helper function to initialize students).
You will need to read up on how pointers work to make sense of it, but that's C for you.
#include <stdio.h>
#include <string.h>
struct st {
char familia[1000];
char imia[1000];
char otchestvo[1000];
int gruppa;
int grozhdenia;
};
static void assign_student(struct st *student, const char *familia, const char *imia, const char *otchestvo, int gruppa, int grozhdenia) {
// TODO: use strncpy
strcpy(student->familia, familia);
strcpy(student->imia, imia);
strcpy(student->otchestvo, otchestvo);
student->gruppa = gruppa;
student->grozhdenia = grozhdenia;
}
static void print_student(struct st *student) {
printf("Student: %s %s %s, %d, %d \n", student->imia, student->otchestvo,
student->familia, student->gruppa, student->grozhdenia);
}
int main() {
struct st students[3];
assign_student(&students[0], "Putin", "Vladimir", "Vladimirovich", 40040, 1952);
assign_student(&students[1], "Gordon", "Dymitro", "Aleksandrovich", 50050, 1953);
assign_student(&students[2], "Emelianenko", "Fedor", "Olegovich", 60060, 1950);
for (int i = 0; i < 3; i++) {
print_student(&students[i]);
}
return 0;
}

C programming : Creating substring

I'm new in C and I need some explanation on what I am doing wrong.
I'm trying to iterate over a string and find the first '\' then make a substring from that place in the array.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
struct info{
char* name;
char* type;
char* path;
};
struct info user1;
char* a = "/home/users/user1";
for (int i = strlen(a) ; i < 0 ; i--) {
printf("%d",i);
if(strcmp(a[i],'/')==0){
strncpy(a,user1.name,i);
break;
}
}
return 0;
}
There are many errors I will explain them one by one. The code will be something like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
struct info{
char* name;
char* type;
char* path;
};
struct info user1;
user1.name = malloc(40);
if( user1.name == NULL){
fprintf(stderr, "%s\n","Error in malloc" );
exit(1);
}
const char* a = "/home/users/user1";
for(int i = strlen(a) -1; i >= 0 ; i--) {
if(a[i]=='/'){
strncpy(user1.name,a+i+1,i);
user1.name[i]='\0';
break;
}
}
printf("%s\n",user1.name );
free(user1.name);
return 0;
}
Things you did wrong
There was no memory allocated to name it was simply an uninitialized pointer. Here we have allocated memory to it.
Second thing, strcmp as the name suggests compares null terminated char array not char-s. It can be done with simple == operator.
The copy part is modified to only copy the user name part nothing else. That's why we have incremented the pointer to point to the correct position.
You forgot to check the return value of malloc and then you should free the allocated memory.
Also you can't modify a string literal because it stays in non-modifiable portion of the memory.
try this,
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
struct info{
char* name;
char* type;
char* path;
};
struct info user1;
user1.name = malloc(10);
char* a = "/home/users/user1";
int len=strlen(a);
for (int i = 0; i < len; i++) {
printf("%d",i);
if(a[i]=='/'){
strncpy(user1.name,a+i+1,i);
user1.name[i]='\0';
break;
}
}
return 0;
}

C segmentation fault 11 when implementing hashtable

Doing a relational data structures project where I organize things into a hashtable. So far I've made an insert and lookup method and have no errors. When I try to run the code however I get this:
"Inserting CSG touples"
"segmentation fault 11"
I assume I'm not mallocing something correctly but I can't figure out what and considering it is saying "inserting CSG touples" I don't think its a problem in my createHashTable function. Heres my code
header file: CSG.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct CSG{
char* Course;
char* StudentId;
char* Grade;
struct CSG *next;
}CSG;
typedef struct CSGHASH{
int size;
CSG** table;
}CSGHASH;
CSGHASH* createHashTable(int size);
int hash(int CN);
CSG* makeCSG(char* Course, char* StudentId, char* Grade);
void printCSG(CSG guy);
//void printCSGLIST(CSGLIST guy);
int toInt(char* x);
CSG* lookup(CSGHASH *hashtable, char* course, char* StudentId, char* grade);
int insert(CSG* newGuy, CSGHASH* hashtable);
CSG.c
CSGHASH* createHashTable(int size){
CSGHASH* hashtable = NULL;
if(size<1)
return NULL; // table cant be less than length of 1
if((hashtable = malloc(sizeof(CSGHASH*)))== NULL)
return NULL;
if((hashtable->table = malloc(sizeof(CSG*) * size)) == NULL)
return NULL;
for(int i = 0; i<size; i++){
hashtable->table[i] = malloc(sizeof(CSG));
hashtable->table[i] = NULL;
//hashtable->table[i]->next = NULL;
}
hashtable->size = size;
return hashtable;
}
int hash(int CN){
return CN%6;
}
CSG* makeCSG(char* Course, char* StudentId, char* Grade){
//struct CSG tempCSG = malloc(sizeof(CSG));
CSG* tempCSG = malloc(sizeof(CSG*));
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
return tempCSG;
}
void printCSG(CSG guy){
printf("course: %s\n", guy.Course);
printf("StudentId: %s\n", guy.StudentId);
printf("Grade: %s\n", guy.Grade);
}
// void printCSGLIST(CSGLIST guy){
// }
int toInt(char* x){
int count = 0;
for(int i = 0; i< strlen(x); i++)
count += (int) i;
return count;
}
CSG* lookup(CSGHASH *hashtable, char* course, char* StudentId, char* grade){
CSG* list;
unsigned int hashNum = hash(toInt(course));
for(list = hashtable->table[hashNum]; list!= NULL; list = list->next){
if(strcmp(StudentId, list->StudentId) == 0){
printf("Course: %s\n", list->Course);
printf("Student ID: %s\n", list->StudentId);
printf("Grade: %s\n", list->Grade);
return list;
}
}
printf("doesn't exist\n");
return NULL;
}
int insert(CSG* newGuy, CSGHASH* hashtable){
CSG* list;
CSG* currList;
unsigned int hashNum = hash(toInt(newGuy->Course));
list = malloc(sizeof(CSG));
currList = lookup(hashtable, newGuy-> Course, newGuy-> StudentId, newGuy-> Grade);
if(currList != NULL){
printf("already exists\n");
return 2;
}
list->Grade = strdup(newGuy->Grade);
list->StudentId = strdup(newGuy->StudentId);
list->Course = strdup(newGuy->Course);
list->next = hashtable->table[hashNum];
hashtable->table[hashNum] = list;
printf("CSG inserted\n");
return 0;
}
main file
/*
main4.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include"CSG.h"
int main(int argc, char *argv[]){
CSGHASH *testHash = createHashTable(47);
printf("inserting CSG tuples \n");
CSG* tuple1 = makeCSG("CSC101", "12345", "A+");
CSG* tuple2 = makeCSG("CSC101", "67890", "B");
CSG* tuple3 = makeCSG("EE200", "67890", "B+");
CSG* tuple4 = makeCSG("EE200", "45213", "D");
CSG* tuple5 = makeCSG("CSC173", "98765", "C");
CSG* tuple6 = makeCSG("MTH142", "47474", "A");
insert(tuple1, testHash);
lookup(testHash, "CSC101", "12345", "*");
//printCSGLIST(lookup(tester, "CSC101", "12345", "*"));
}
If someone can figure out what I'm doing wrong I'd really appreciate it (sorry I know its a lot to trace through).
UPDATE
after a little debugging it would appear the issue is in the makeCSG function. Hope that makes it a little easier to trace through
A fast pass turned up:
if((hashtable = malloc(sizeof(CSGHASH*)))== NULL)
Err, this will allocate enough storage for a pointer to the CSGHASH and not the CSGHASH itself. Think you want to get rid of the asterisk. The following malloc() will also suffer the same fate.
From CSG.h:
typedef struct CSG{
char* Course;
char* StudentId;
char* Grade;
struct CSG *next;
}CSG;
and in makeCSG() you are doing:
CSG* makeCSG(char* Course, char* StudentId, char* Grade){
//struct CSG tempCSG = malloc(sizeof(CSG));
CSG* tempCSG = malloc(sizeof(CSG*));
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
return tempCSG;
}
There are couple of problems in makeCSG():
First problem:
CSG* tempCSG = malloc(sizeof(CSG*));
Here, tempCSG is a pointer pointing to CSG. So you should:
CSG* tempCSG = malloc(sizeof(CSG));
Similar issue in createHashTable():
if((hashtable = malloc(sizeof(CSGHASH*)))== NULL)
this should be:
if((hashtable = malloc(sizeof(CSGHASH)))== NULL)
Second problem:
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
Here, Course, StudentId and Grade are of type char * and you are trying to copy some value to pointers whom you have not allocated memory. Allocate memory before using them.
So first you should do something like this:
CSG* tempCSG = malloc(sizeof(CSG));
tempCSG->Course = malloc(100);
tempCSG->StudentId = malloc(20);
tempCSG->Grade = malloc(10);
and then
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
tempCSG->next = NULL;
Also, make sure to check the malloc return after every malloc call.
Basically everything envolving char* is wrong. You are not allocating the memory necessary to copy data into those buffers, in fact you are not initializing them at all.
A simplified version of whats wrong with your code:
char* Course;
strcpy(Course, "CSC101");
This is bond to cause fatal errors because we never allocated Course.
You have to either malloc() enough space to fit data in there, for each one of the char* in the structure, or declare them as arrays, so they are already allocated as you reserve memory for the structure they are in, but will have a fixed size determined at compile time.
Example:
typedef struct CSG
{
char Course[16];
char StudentId[16];
char Grade[16];
struct CSG *next;
} CSG;
This really is the easiest way to approach the problem, allows easy store and recover of this structure on a file if you wish to create some sort of basic database, and keeps the code cleaner, avoiding excessive memory management from a ton of malloc() and free() all over the place.

Segmentation fault while referencing and adding values to a structure

Okay, so the problem concerns adding values through function to structure. Honestly, I couldn't solve the problem (spent a lot of time trying), so I am asking for your help. While executing the program, I get a segmentation fault. It occurs while using the variables from stack stos.
typedef struct e {
int zaglebienie[100];
char *nazwa_funkcji[100];
int poz;
} *stack;
void put_on_fun_stack(int par_level, char *funame, stack stos) {
int i = stos->poz;
stos->zaglebienie[i] = par_level;
char *funkcja = strdup(funame);
stos->nazwa_funkcji[i] = funkcja;
stos->poz++;
}
int main() {
char *p = "makro";
stack stos;
stos->zaglebienie[0] = 0;
put_on_fun_stack(1, p, stos);
return 0;
}
You're declaring a pointer to stack but you're not allocating any memory to it.
And as already mentioned in the comments, using typedef with with a pointer will unnecessarily complicate your life.
So I suggest you create the struct stack and then in main declare a pointer to stack and allocate memory for it, somewhat like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct e {
int zaglebienie[100];
char *nazwa_funkcji[100];
int poz;
} stack;
void put_on_fun_stack(int par_level, char *funame, stack *stos)
{
int i = stos->poz;
stos->zaglebienie[i] = par_level;
char *funkcja = strdup(funame);
stos->nazwa_funkcji[i] = funkcja;
stos->poz++;
}
int main(void)
{
char *p = "makro";
// calloc to initialize stos variables to 0
stack *stos = calloc(sizeof(stack), 1);
printf("stos->poz before: %d\n", stos->poz);
put_on_fun_stack(1, p, stos);
printf("stos->poz after: %d\n", stos->poz);
printf("stos->nazwa_funkcji[0]: %s\n", stos->nazwa_funkcji[0]);
free(stos->nazwa_funkcji[0]);
free(stos);
return 0;
}
Output:
stos->poz before: 0
stos->poz after: 1
stos->nazwa_funkcji[0]: makro

merging of text

Can you please help me with merging of two texts into one using just only stdio.h and stdlib.h? The result should be HelloWorld.
So far, I have the following, but there is a mistake somewhere.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char *spojeni(char *t1, char *t2)
{
char pole_spolecne[10];
for (*t1 = 0; *t1 < 5; t1++)
{
pole_spolecne[*t1] = *t1;
}
for (*t2 = 0; *t2 < 10; t2++)
{
pole_spolecne[*t2 + 5] = *t2;
}
return pole_spolecne;
}
int main()
{
char pole1[] = { "Hello" };
char pole2[] = { "World" };
printf("%s\n", spojeni(pole1, pole2));
system("pause");
return 0;
}
My new solution, but it returns an error at the end:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char *spojeni(char *t1, char *t2)
{
char pole_cele[20];
char *p_pole_cele;
p_pole_cele = t1;
strcat(p_pole_cele, t2);
return p_pole_cele;
}
int main()
{
char pole1[] = { "Hello" };
char pole2[] = { "World" };
char *p_pole1;
char *p_pole2;
p_pole1 = pole1;
p_pole2 = pole2;
printf("%s\n)", spojeni(p_pole1, p_pole2));
system("pause");
return 0;
}
Finally, this change of function helped:
char *spojeni(char *t1, char *t2)
{
char pole_cele[20];
char *p_pole_cele;
p_pole_cele = (char *)malloc(10);
strcpy(p_pole_cele, t1);
p_pole_cele = (char *)realloc(p_pole_cele, 20);
strcat(p_pole_cele, t2);
return p_pole_cele;
}
I am not quite sure how to answer this, as this is clearly a teaching exercise, and, to be blunt, the code given shows a lack of understanding of pointers. And pointers is a topic better taught in person than via a web-site comment.
A few hints, though:
Think very clearly about pointers, what they are pointing to, and what makes them different from array indices.
Draw diagrams to visualize what you're doing.
Your exercise can be solved using calloc(), strlen() and strcpy().

Resources