Practice Exam Questions - c

This is a practice exam question that I am having some difficulty with:
struct bodytp // Is there an error?
{
char *name; // If so, fix the error.
int len;
};
main()
{
struct bodytp person;
keepname(&person , "Waterman");
printf("%s\n", person.name);
}
void keepname(struct bodytp *onept, const char *last)
{
int len;
char *tpt;
for ( len = 0; last[len] != '\0'; )
len++;
char name[len+1];
for ( tpt = name; *tpt++ = *last++; )
;
onept->name = name;
onept->len = len;
}
I have determined that there is an error, as when I run it, I get garbage output from printf. I have also determined that person's name is indeed "Waterman" after the keepname function call. I have tried dereferencing person.name to person -> name, changing the problem from a stack-based question to a heap-based question by eliminating the ampersand operator and malloc-ing the struct, but nothing worked. Can anyone steer me in the right direction? Thank you in advance.

Is there an error?
struct bodytp // Is there an error?
{
char *name; // If so, fix the error.
int len;
};
No there is no error. It is a valid structure definition.
Now errors follow.:)
Function main shall be declared as
int main( void )
Though it is not an error nevertheless it would be better that before the function call there woud be the function prototype
keepname(&person , "Waterman");
The program has undefined behaviour because there is an assignment of a pointer to the structure by the address of a local array that will be destroyed after exiting the function
void keepname(struct bodytp *onept, const char *last)
{
//...
char name[len+1];
//...
onept->name = name;
//...
}
The valid function could be defined like
void keepname(struct bodytp *onept, const char *last)
{
int len = 0;
char *tpt;
while ( last[len] != '\0' ) len++;
char *name = malloc( len + 1 );
for ( tpt = name; *tpt++ = *last++; ) ;
onept->name = name;
onept->len = len;
}
In this case you have to free the alocated memory in main.
Take into account that you coud use standard C functions strlen and strcpy in the function.

You need to allocate the memory for the name in the heap.
void keepname(struct bodytp *onept, const char *last)
{
int len;
char *tpt;
for ( len = 0; last[len] != '\0';len++);
char *name=malloc(len+1);
onept->name = name;
onept->len = len;
for ( ; *name++ = *last++ ; );
}

Related

Table of structures (realloc in C)

i am trying to write a code in C but i am having some problems with realloc. I had to write a code that will create a stack, and will add to it (dodaj_do_stosu), reamove from it (usun_ze_stosu) and will look at the top thing that is on this stack. I have problem with compiling(it does work for first two words but then it returns (0xC0000374)).
I think i am usining the realloc wrong and the sizeof my structure. If someone could look at my code (especially at the function (dodaj_do_stosu) and tell me what am i doing wrong thx. My code look like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
int n;
char *nazwa;
}element_t;
typedef struct {
int rozmiar;
element_t **tablica;
}stos_t;
void top_of_stack(stos_t *s){
printf("ostatni element stosu:rozmiar = %d nazwa=%s, n=%d\n", s->rozmiar, s->tablica[s->rozmiar]->nazwa, s->tablica[s->rozmiar]->n);
}
void init(stos_t *s)
{
s->rozmiar=0;
s->tablica=malloc(0);
}
void dodaj_do_stosu(stos_t *s, int n, char *name)
{
s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof(s->tablica));
s->tablica[s->rozmiar]->nazwa = name;
s->tablica[s->rozmiar]->n = n;
printf("rozmiar=%d, n=%d , nazwa=%s\n",s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa);
s->rozmiar++;
}
void usun_ze_stosu(stos_t *s)
{
s->tablica = realloc(s->tablica, (s->rozmiar - 1) * sizeof(s->tablica[0]));
s->rozmiar--;
}
void rm(stos_t s)
{
free(s.tablica);
}
int main(int argc, char **argv)
{
stos_t s;
init(&s);
int i;
srand(time(0));
if (argc>1)
for(i=1;i<argc;i++){
printf("%s\n", argv[i]);
dodaj_do_stosu(&s, rand() % 10, argv[i]);
}
for(i=0;i<argc-1;i++){
//printf("i=%d, n=%d, nazwa=%s\n",i, s.tablica[i].n, s.tablica[i].nazwa);
}
//top_of_stack(&s);
//usun_ze_stosu(&s);
//top_of_stack(&s);
rm(s);
return 0;
}
A big part of your problem is that tablica is an array of pointers, but you never initialize the pointers themselves.
The dodaj_do_stosu function reallocates the array, but doesn't create the element_t objects. Therefore any dereference of e.g. s->tablica[s->rozmiar] will lead to undefined behavior.
There are two possible solutions:
Allocate a new element_t structure:
s->tablica[s->rozmiar] = malloc(sizeof(element_t));
before you initialize the element_t structure members.
Make tablica an array of structure objects instead of pointers:
element_t *tablica; // tablica is an array of objects, not an array of pointers
I recommend solution 2.
At least the function dodaj_do_stosu is wrong. The data member tablica is declared like
element_t **tablica;
So the expression s->tablica[s->rozmiar] has the type element_t * and an indeterminate value. Thus dereferencing the pointer expression for example like
s->tablica[s->rozmiar]->nazwa
invokes undefined behavior.
You have to allocate memory for objects of the structure type element_t not for pointers of the type element_t *.
So you need to declare the data member like
element_t *tablica;
and within the function to write
s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof( *s->tablica));
Also it is safer to use an intermediate pointer for calls of realloc.
The function can look the following way
int dodaj_do_stosu( stos_t *s, int n, char *name )
{
element_t *tmp = realloc( s->tablica, ( s->rozmiar + 1 ) * sizeof( *s->tablica ) );
int success = tmp != NULL;
if ( success )
{
s->tablica = tmp;
s->tablica[s->rozmiar]->nazwa = name;
s->tablica[s->rozmiar]->n = n;
printf("rozmiar=%d, n=%d , nazwa=%s\n", s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa );
++s->rozmiar;
}
return success;
}
Consequently the function should be redefined at least the following way. As is it can for example invoke undefined behavior when s->rozmiar is equal to 0.
int usun_ze_stosu( stos_t *s )
{
int success = s->rozmiar != 0;
if ( success )
{
element_t *tmp = realloc( s->tablica, ( s->rozmiar - 1 ) * sizeof( *s->tablica ) );
success = tmp != NULL;
if ( success )
{
s->tablica = tmp;
--s->rozmiar;
}
}
return success;
}
Also within the function init it will be much better ro write
void init(stos_t *s)
{
s->rozmiar=0;
s->tablica = NULL;
}
Another problem is the function rm
void rm(stos_t s)
{
free(s.tablica);
}
You should pass the original object through a pointer to it and within the function to write
void rm(stos_t *s)
{
free( s->tablica );
s->tablica = NULL;
s->rozmiar = 0;
}

I am stuck in this codes in GCC

I was testing the code in GCC in Linux. So far so good, Here is simple SLOC that i tried to achive...
After running the code output is:
<1>
<>
<>
But more impressively when i change order of printf lines giving different results...
What is wrong with this code and about this situation could you please assit me...
Thanks
Regards.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *vbStrReverse(char *pBuffer);
int main(){
printf("<%s>",vbStrReverse("1"));
printf("<%s>",vbStrReverse("123456"));
printf("<%s>",vbStrReverse(""));
}
char *vbStrReverse(char *pBuffer){
int size=strlen(pBuffer);
char *ptr =(char*) malloc(sizeof(char)*size+1);
int i;
int ax;
do
{
ax=*(pBuffer+i);
if (ax=='\0'){
*(ptr+i+1)='\0';
break;
}
*(ptr+i)=*(pBuffer+size-i-1);
i++;
} while (1);
return(ptr);
}
The function has undefined behavior.
For starters the variable i was not initialized
int i;
It seems you mean
int i = 0;
In this statement
*(ptr+i+1)='\0';
a garbage can be included in the array pointed to by the pointer ptr for example when the source string is empty and the memory beyond the allocated array will be overwritten
The function can be declared and defined the following way
char * vbStrReverse( const char *pBuffer )
{
size_t size = strlen( pBuffer );
char *ptr = malloc( size + 1 );
if ( ptr != NULL )
{
ptr += size;
*ptr = '\0';
while ( *pBuffer )
{
*--ptr = *pBuffer++;
}
}
return ptr;
}

problem in returning array address from function in C

There comes an error "conflicting types" so what can I do, and prefer a good alternative for this. The main problem is in returning an array from function
#include<stdio.h>
int* freqofchar(char);
int main()
{
char str[100];
printf("Enter a sentence below :\n");
gets(str);
int* p = freqofchar(str);
for(int i=0;i<128;i++){
if(*p>0){
printf("%c occurred %d times\n",(char) i , *p++);
}
}
return 0;
}
int* freqofchar(char str[]){
int freq[128] = {0};
for(int i = 0;str[i] != '\0';i++){
freq[ str[i] ]++;
}
return freq;
}
You have 2 problems:
1) conflicting types:
int* freqofchar(char)
in declaration, but
int* freqofchar(char str[])
in definition.
2) You are returning freq allocated on stack from freqofchar
The error you see is due to mismatch in the function prototype and its actual definition.
However, you have other problems, too:
gets function has been removed from the C standard (since) for a good reason and should never be used in any case. You can use fgets instead to read input. But you need to remove the newline if fgets reads it in.
You are returning a pointer to a local variable, whose lifetime isn't valid once the function freqofchar returns, which is undefined behaviour. You can instead pass another argument. Generally you may want to consider dynamic allocation (e.g. via malloc) but in this case - you only need a small array - an array local to the main function, which has automatic storage duration and thus its lifetime is valid for the duration of main() and it can be safely passed to freqofchar function without it being invalid or de-allocated as the object's (freq being the object in reference here) lifetime is still valid in when it's being used in freqofchar() - is better-suited here.
Here's how a fixed solution would looks like:
#include<stdio.h>
#include<string.h>
void freqofchar(char*, int*);
int main()
{
char str[100] = {0};
int freq[256] = {0};
printf("Enter a sentence below :\n");
fgets(str, sizeof str, stdin);
/* Remove the newline if present. */
char *p = strchr(str, '\n');
if (p) *p = '\0';
freqofchar(str, freq);
for(size_t i = 0;i < sizeof freq; i++) {
if(freq[i]) {
printf("%c occurred %d times\n", i, freq[i]);
}
}
return 0;
}
void freqofchar(char str[], int freq[])
{
for(int i = 0;str[i] != '\0';i++) {
freq[ str[i] ]++;
}
}
The function parameter is declared in the function declaration as having the type char
int* freqofchar(char);
^^^^^
But in the function declaration that at the same is its definition
int* freqofchar(char str[]){
^^^^^^^^^
the parameter is declared as having the type char [] (that is adjusted by the compiler to the type char *).
This typo is the reason of the compiler message.
But in any case the function shall be declared at least like
unsigned int * freqofchar( const char [] );
That is there is no sense to define frequencies as having signed integer type and the parameter shall have the qualifier const because the passed string is not being changed in the function.
The program has undefined behavior because the function returns pointer to a local array with the automatic storage duration that will not be alive after exiting the function.
int* freqofchar(char str[]){
int freq[128] = {0};
//...
return freq;
}
You should either allocate the array dynamically or declare it with the storage specifier static. In the last case you need to reset elements of the array to zeroes each time when the function is called.
The function gets is an unsafe function and is not supported by the C standard any more. Instead use the standard C function fgets.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned int* freqofchar( const char *);
int main( void )
{
enum { N = 100 };
char str[N];
str[0] = '\0';
printf( "Enter a sentence below : " );
fgets( str, N, stdin );
// remove the appended new line character '\n'
str[ strcspn( str, "\n" ) ] = '\0';
unsigned int *p = freqofchar( str );
for ( size_t i = 0; i < 128; i++ )
{
if ( p[i] )
{
printf( "'%c' occurred %u times\n", ( char )i , p[i] );
}
}
free( p );
return 0;
}
unsigned int * freqofchar( const char str[] )
{
enum { N = 128 };
unsigned int *freq = calloc( N, sizeof( unsigned int ) );
while ( *str ) ++freq[ ( size_t )*str++ ];
return freq;
}
Its output might look like
Enter a sentence below : Hello World!
' ' occurred 1 times
'!' occurred 1 times
'H' occurred 1 times
'W' occurred 1 times
'd' occurred 1 times
'e' occurred 1 times
'l' occurred 3 times
'o' occurred 2 times
'r' occurred 1 times
If to define the function with the static storage specifier then its definition can look the following way.
#include <stdio.h>
#include <string.h>
unsigned int* freqofchar( const char *);
int main( void )
{
enum { N = 100 };
char str[N];
str[0] = '\0';
printf( "Enter a sentence below : " );
fgets( str, N, stdin );
// remove the appended new line character '\n'
str[ strcspn( str, "\n" ) ] = '\0';
unsigned int *p = freqofchar( str );
for ( size_t i = 0; i < 128; i++ )
{
if ( p[i] )
{
printf( "'%c' occurred %u times\n", ( char )i , p[i] );
}
}
return 0;
}
unsigned int * freqofchar( const char str[] )
{
enum { N = 128 };
static unsigned int freq[N];
memset( freq, 0, N * sizeof( unsigned int ) );
while ( *str ) ++freq[ ( size_t )*str++ ];
return freq;
}
You make one of the most common mistakes in the C programming. You return the pointer to the object which does not exist after the function return.
possible solutions
a. use dynamicaly allocated memory
int* freqofchar(char *str)
{
int *freq = malloc(128 * sizeof(*freq)); // or if you want to zero it calloc
/* ... */
return freq;
}
but you need to free the allocated memory when not needed.
b. use static array or global array
int* freqofchar(char *str)
{
static freq[128];
/* ... */
return freq;
}
or
static freq[128];
int* freqofchar(char *str)
{
/* ... */
return freq;
}
Downsides of this solution: the function is not reentrant, the freq array cannot be passed to the async task and functions as it can be changed if function is called again.
The initialisation happens only one time before first call to the function.
c. Wrap it in the union or struct and return the whole object
struct freqstruct {
int freq[128];
};
struct freqstruct freqofchar(char *str)
{
struct freqstruct freq = {0};
/* ... */
return freq;
}
Downside - the whole array wrapped into the struct is copied. It is not very memory and performance wise.
Your definition does not match the declaration of the function. It shows that you did not put enough effort.
int* freqofchar(char *str)
int* freqofchar(char *str)
{
/* ... */
}
or - but I personally do not like this notation as it makes beginners think that the array is passed not the pointer.
int* freqofchar(char str[])
int* freqofchar(char str[])
{
/* ... */
}
This functions is not const corrent - the parameter str should be const char *str or const char str[]

Accessing information from nested struct passed to function

I have the following code:
struct wordPair {
char* englishWord;
char* foreignWord;
};
struct dictionary {
struct wordPair ** data;
int nbwords;
int size;
};
Say I have struct dictionary *dictionaryPtr filled with some data, and I pass it to the following function:
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word)
Within the function dictionary_translate, how can I access the data from the struct wordPair that is nested within the passed struct? I need the function to return a strdup of either englishWord or foreignWord.
I was trying d->data->englishWord, but this gives me the error "request for member 'englishWord' in something not a structure or union".
UPDATE!
What I need the function dictionary_translate to do is determine if there is a matching word pair that contains one of the words passed to it, and return the strdup of the translation (the other word in the pair). Here is the array of words I have defined:
const char* test_translations[NB_TESTS][NB_COLS] =
{
{"hello", "hola"},
{"cat", "gato"},
{"dog", "perro"},
{"thanks", "gracias"},
{"pants", "pantalones"},
{"shoes", "zapatos"},
};
This is how I'm calling the function in the first test I'm trying, which is when the translate function is passed an English word and is required to return a foreign word:
char* translationPtr = NULL;
for (i = 0; i < NB_TESTS; i++) {
translationPtr = dictionary_translate(dictionaryPtr, test_translations[i][0], NULL);
printf("English Word %s translated: %s\n", test_translations[i][0], translationPtr);
}
Here is the translate function as I have it so far...
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word){
int i;
if (d == NULL) return NULL;
for (i = 0; i < d->nbwords; i++) {
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return NULL;
}
As soon as the program gets to the translation function, it crashes. I can't make sense of the debugger to find out what is going on, but it seems like translationPtr never has a value other than NULL (0x0). I'm new with the debugger, so I'm sure it could tell me more if I knew how to read it.
It isn't entirely clear what your function is to do, but about the simplest implementation that might legitimately work is:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair **data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
I think you should review the design of your struct dictionary. Using a double pointer seems unnecessary (or the reason for using it is not obvious). The only advantage is that you'd have a contiguous array of pointers to struct wordPair, while the actual struct wordPair elements need not be contiguously allocated themselves. The following code is a more orthodox definition, assuming that a contiguous array of struct wordPair is not a problem:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair *data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i].englishWord) == 0)
return strdup(d->data[i].foreignWord);
else if (strcmp(foreign_word, d->data[i].foreignWord) == 0)
return strdup(d->data[i].englishWord);
}
return 0;
}
Given the sample test code where one of the arguments to dictionary_translate() is a NULL pointer, the code in the function must be revised not to dereference the argument if it is null. This assumes the double-pointer version of struct dictionary.
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (englishWord != NULL && strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (foreignWord != NULL && strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
d->(*data)->englishWord
Should compile.

C -- Structs and Pointers Basic Questions

So I'm trying to learn C right now, and I have some basic struct questions I'd like to clear up:
Basically, everything centers around this snippet of code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN 127
typedef struct {
char name[MAX_NAME_LEN + 1];
unsigned long sid;
} Student;
/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
return s->name; // returns the 'name' member of a Student struct
}
/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct | 'name' is a pointer to the first element of a char array (repres. a string)
char temp;
int i;
for (i = 0, temp = &name; temp != '\0'; temp++, i++) {
*((s->name) + i) = temp;
}
/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
return s->sid;
}
/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
s->sid = sid;
}
I've commented up the code in an attempt to solidify my understanding of pointers; I hope they're all accurate.
Also, I have another method,
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
which I'm sure is wrong in some way... I also think my setName is implemented incorrectly.
Any pointers? (no pun intended)
This is very wrong. If you insist on not using strcpy do something like this (not tested)
int iStringLength = strlen(name);
for (i = 0; i < iStringLength; i++) {
s->name[i] = name[i];
}
but make sure that the length is not longer than your array size.
This is also wrong
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
because the s object is destroyed when the function exits - it is local to the function scope and yet you return a pointer to it. So if you try to access the struct using this pointer it will not be valid as the instance no longer exists. If you want to do this you should dynamically allocate it using malloc . Alternatively do not return a pointer at all and use the alternative option of #Andrew .
In your "another method" you are locally declaring Student s, which will dynamically allocate space (usually on the stack) and you are returning that address on completion.
However, that stack-space will be released on the return, so there is no guarantee that the data is uncorrupted - in fact the likelyhood is that it will be!
Declare Student s in the call to your method, and pass the pointer to makeAndrew:
void makeAndrew(Student *s) {
setName( s, "Andrew");
setStudentID( s, 12345678);
}
...
Student s;
makeAndrew( &s );
...
Your function makeAndrew returns pointer to a local variable. It is only valid before the scope ends, so as soon as the function finishes, it will change when the memory gets overwritten - i. e. almost instantly. You would have to allocate it dynamically (using Student *s = new Student;, or if you really want to stick to pure C, Student *s = malloc (sizeof Student );, and then free it outside the function after it is not needed to avoid memory leak.
Or do it as Andrew suggested, it's less error-prone.
I would change the makeAndrew() function to just return a struct, not a pointer to a struct to correct the error with respect to returning a pointer to a temporary variable:
Student makeAndrew(void)
{
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return s;
}
Student aStudent = makeAndrew();
Your setName does have an error with respect to temp, which should be a char *, since you are incrementing it in your loop to point to another character in the input c-string. I think it was missing the null termination as well. And as you mention in your comment, there should be a check for overflow of the name char array in Student:
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |
// 'name' is a pointer to the first element of a char array (repres. a string)
const char *temp;
int i;
for (i = 0, temp = name; *temp != '\0' && i <= MAX_NAME_LEN; temp++, i++)
{
*((s->name) + i) = *temp;
}
s->name[i] = '\0';
}
You can use strncpy to simplify setName:
void setName2(Student *s,const char *name)
{
#include <string.h>
strncpy(s->name, name,MAX_NAME_LEN);
s->name[MAX_NAME_LEN] = '\0';
}

Resources