Assert - segmentation fault - c

I've got an issue i can't handle so i've thought maybe you can help me. Basically i have a function that receives a char* as a paramater and does some stuff to it(i've checked those steps/functions and they work just fine).If the char* given in the function is ""(i guess NULL), i receive seg fault with assert.
Here is the code:
char *computeRNA(char *s)
{
if (s != NULL && s!= "")
{
Lista* l = to_list(s);
int i;
l = l->next;
for(i = 0; i<= lungime(l); ++i)
{
if(l->info == 'T')
l->info = 'U';
l = l->next;
}
char *rna = to_pointer(l);
return rna;
}
return NULL;
}
And here is the assert:
char *s;
s = computeRNA("");
ASSERT(!strcmp(s, ""), "computeRNA-01");
free(s);
This is a school homework so i can not change assert's code , only the function.Thanks in advance !

This ASSERT that you weren't supposed to be changing, tests that if an empty string is given to computeRNA it should also return an empty string:
s = computeRNA("");
ASSERT(!strcmp(s, ""), "computeRNA-01");
Your code returns null pointer. Also comparing strings needs to be done using strcmp, s == "" would only compare pointer values that wouldn't be of use here.
Thus I'd start the function with
// null pointer was given
if (!s) {
return calloc(1, 1);
}
// an empty string was given (the first character pointed to b s is the string terminator.)
// to compare explicitly, you need to do `strcmp(s, "")` == 0. `s == ""` is wrong.
if (!*s) {
return "";
}

You cannot pass a NULL pointer to strcmp() as argument. Before the ASSERT statement, just check for non-NULL value of s. Something like
if (s) {
ASSERT(!strcmp(s, ""), "computeRNA-01");
}
should do the job.
EDIT:
In case changing the function using the assertion is also not possible, you can modify the computeRNA() function to return an empty string, instead of NULL, like
char * empty_string = calloc(1,1);
return empty_string;
which can later be passed to free() in the caller.

Related

What is the difference between char word[25]; and char word[25] = "";?

I'm trying various code to check Palindrome words, sure there are so many ways to code it, I somehow find something that triggers my curiosity but I couldn't find any answer somewhere although the code run good
That's found that there's a slight differences between two array of char wordReverse declaration below.
Could anyone give an explanation of these two declarations?
bool checkPallen(char word[]){
char wordReverse[25] = ""; //error if used char wordReverse[25];
int revCount = 0;
for(int i = strlen(word) - 1; i >= 0; i--){
wordReverse[revCount] = word[i]; //
revCount++;
}
if(strcmp(wordReverse, word) == 0) return true;
return false;
}
The difference is that uninitialized local variables have indeterminate values.
When you read from wordReverse,
strcmp(wordReverse, word)
strcmp takes two strings, i.e. it expects to find a NUL terminator somewhere.
Your loop that fills wordReverse doesn't terminate it, so you get undefined behavior here.
Fix:
wordReverse[revCount] = '\0';
after the loop.
The version that initializes wordReverse as
char wordReverse[25] = "";
works because it is equivalent to char wordReverse[25] = { '\0' }, which sets the first element to '\0' explicitly and all remaining elements to '\0' implicitly.
NB:
if (X) return true;
return false;
is equivalent to
return !!X; // Returns 1 if and only if X is not 0, and 0 otherwise

Strcat issues when concatenating

Hi for some reason Strcat does not like the value property within my structure. I'm not sure why. Here is my structure code:
typedef struct TrieSearchTree{
char value;
struct DynamicList* children;
};
and here is my method:
void PrintDynamicListContents(struct DynamicList* dynamicList, char* word)
{
struct dynamicListNode* currentRecord;
struct TrieSearchTree* trieSearchTree;
struct dynamicListNode* nextRecord = dynamicList->head;
while(nextRecord != NULL)
{
currentRecord = nextRecord;
nextRecord = currentRecord->next;
trieSearchTree = currentRecord->entity;
if (trieSearchTree != NULL)
{
if (trieSearchTree->value != WORD_END_CHAR)
{
char c[CHAR_LENGTH] = "";
strcat_s(c, CHAR_LENGTH, word);
strcat_s(c, CHAR_LENGTH, trieSearchTree->value);
PrintDynamicListContents(currentRecord, c);
}
else
{
printf("%s", word);
}
}
}
}
Here is the error message:
Proof that the value from the structure returns something (the 'l' character)
I've been trying to get strcat working for hours and I can't get it to work even reading the online tutorials. All help appreciated.
The strcat_s function expects a char *, specifically a pointer to a null terminated string, as the third argument. You're passing in a single char. Your compiler should have warned you about this.
That character is being interpreted as a pointer and being dereferenced. This invokes undefined behavior, which in this case manifests in a crash.
If you want to append a single character to a string, you need to add it and a new null terminator manually.
char c[CHAR_LENGTH] = "";
strcat_s(c, CHAR_LENGTH, word);
c[strlen(c) + 1] = '\0';
c[strlen(c)] = trieSearchTree->value;

Printing null if a character is null

I have a function written in C that returns either a pointer to a value or null;
char* function (char const *source char const *chars)
{
int size();
int sizeSource = size(source);
int charSource = size(chars);
for (int i = 0; i < sizeSource; i++)
{
for (int j = 0; j < charSource; j++)
{
if (*(source + i) == *(chars + j))
{
return *(source + i);
}
}
}
return "NULL";
}
The function works just fine and I am calling it in this manner:
printf("%c\n", function("ABCDEFG", "HJI"));
printf("%c\n", function("ABCDEFG", "ABC"));
So just to explain here, the first print statement is returning null since HJI is not in ABC and the second returns a pointer to A which is fine. My question is when I currently run it the first print statement just prints nothing, is there some sort of way I can make it print "NULL" if it comes back NULL? I'd rather not have to check each return value for NULL before I print it.
edit: I would like to keep it consistent between success and failure cases. If I change %c to %s in success cases that return a pointer I get a segmentation fault. I also would like to return something not print output in the function.
change %c to %s and return the text string "NULL".
Something like:
static void print_char_or_null(const char *s)
{
if (s) { /* you can use "if (s != NULL)" if you prefer */
putc(*s, stdout);
} else {
printf("NULL");
}
}
And change function to return NULL (not "NULL") in case of failure.
Then you can do:
print_char_or_null(function("ABCDEFG", "HJI"));
print_char_or_null(function("ABCDEFG", "ABC"));
Something ugly:
#define PRINT_CHAR_OR_NULL(pc) \
printf((pc) ?"%c" :"%s", (pc) ?*(pc) :"NULL")
...
char * p = <assign as per OP's requirements>
PRINT_CHAR_OR_NULL(p);
To use this instead of "NULL" return NULL.

Appending a char to a char* in C?

I'm trying to make a quick function that gets a word/argument in a string by its number:
char* arg(char* S, int Num) {
char* Return = "";
int Spaces = 0;
int i = 0;
for (i; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
//Want to append S[i] to Return here.
}
else if (Spaces > Num) {
return Return;
}
}
printf("%s-\n", Return);
return Return;
}
I can't find a way to put the characters into Return. I have found lots of posts that suggest strcat() or tricks with pointers, but every one segfaults. I've also seen people saying that malloc() should be used, but I'm not sure of how I'd used it in a loop like this.
I will not claim to understand what it is that you're trying to do, but your code has two problems:
You're assigning a read-only string to Return; that string will be in your
binary's data section, which is read-only, and if you try to modify it you will get a segfault.
Your for loop is O(n^2), because strlen() is O(n)
There are several different ways of solving the "how to return a string" problem. You can, for example:
Use malloc() / calloc() to allocate a new string, as has been suggested
Use asprintf(), which is similar but gives you formatting if you need
Pass an output string (and its maximum size) as a parameter to the function
The first two require the calling function to free() the returned value. The third allows the caller to decide how to allocate the string (stack or heap), but requires some sort of contract about the minumum size needed for the output string.
In your code, when the function returns, then Return will be gone as well, so this behavior is undefined. It might work, but you should never rely on it.
Typically in C, you'd want to pass the "return" string as an argument instead, so that you don't have to free it all the time. Both require a local variable on the caller's side, but malloc'ing it will require an additional call to free the allocated memory and is also more expensive than simply passing a pointer to a local variable.
As for appending to the string, just use array notation (keep track of the current char/index) and don't forget to add a null character at the end.
Example:
int arg(char* ptr, char* S, int Num) {
int i, Spaces = 0, cur = 0;
for (i=0; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
ptr[cur++] = S[i]; // append char
}
else if (Spaces > Num) {
ptr[cur] = '\0'; // insert null char
return 0; // returns 0 on success
}
}
ptr[cur] = '\0'; // insert null char
return (cur > 0 ? 0 : -1); // returns 0 on success, -1 on error
}
Then invoke it like so:
char myArg[50];
if (arg(myArg, "this is an example", 3) == 0) {
printf("arg is %s\n", myArg);
} else {
// arg not found
}
Just make sure you don't overflow ptr (e.g.: by passing its size and adding a check in the function).
There are numbers of ways you could improve your code, but let's just start by making it meet the standard. ;-)
P.S.: Don't malloc unless you need to. And in that case you don't.
char * Return; //by the way horrible name for a variable.
Return = malloc(<some size>);
......
......
*(Return + index) = *(S+i);
You can't assign anything to a string literal such as "".
You may want to use your loop to determine the offsets of the start of the word in your string that you're looking for. Then find its length by continuing through the string until you encounter the end or another space. Then, you can malloc an array of chars with size equal to the size of the offset+1 (For the null terminator.) Finally, copy the substring into this new buffer and return it.
Also, as mentioned above, you may want to remove the strlen call from the loop - most compilers will optimize it out but it is indeed a linear operation for every character in the array, making the loop O(n**2).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *arg(const char *S, unsigned int Num) {
char *Return = "";
const char *top, *p;
unsigned int Spaces = 0;
int i = 0;
Return=(char*)malloc(sizeof(char));
*Return = '\0';
if(S == NULL || *S=='\0') return Return;
p=top=S;
while(Spaces != Num){
if(NULL!=(p=strchr(top, ' '))){
++Spaces;
top=++p;
} else {
break;
}
}
if(Spaces < Num) return Return;
if(NULL!=(p=strchr(top, ' '))){
int len = p - top;
Return=(char*)realloc(Return, sizeof(char)*(len+1));
strncpy(Return, top, len);
Return[len]='\0';
} else {
free(Return);
Return=strdup(top);
}
//printf("%s-\n", Return);
return Return;
}
int main(){
char *word;
word=arg("make a quick function", 2);//quick
printf("\"%s\"\n", word);
free(word);
return 0;
}

Returning a String from function in C

char* clean_string (char *input_string){
/*Ensure that input string isn't null and only do heavy lifting if it's not null*/
if (input_string){
char *stripped;
stripped = (char*)malloc(strlen(input_string)*sizeof(char));
while (*input_string != '\0'){
if isalpha(*input_string){
*stripped = toupper(*input_string);
input_string++;
stripped++;
} else {
input_string++;
}
}
/* *stripped++ += '\0';*/
return stripped;
}
/*default return val*/
return NULL;
}
Can anybody tell me where I'm going wrong with this? Tried to do a test run and it doesn't output anything when I try to call it.
You are returning a pointer to the last character in the string (stripped++ ?).
You are allocating one byte too few (should be strlen(...) + 1).
stripped = (char*)malloc(strlen(input_string)*sizeof(char)); /* Wrong. */
stripped = (char*)malloc(strlen(input_string) + 1);
/* .. */
stripped++;
/* .. */
return stripped;
Try to keep a copy, something like original_stripped = stripped before starting to change stripped, and return the copied value (not the incremented one).
The problem is with calling stripped++. You are modifying the pointer you get by malloc. Make an extra pointer char *result_char = stripped; and use that for iteration over resulting string.
The problem ís that you increment your stripped variable before returning it.
Try:
char *stripped;
char *result;
stripped = (char*)malloc(strlen(input_string)*sizeof(char));
result = stripped;
...
return result;
How about just:
char* clean_string (char *input_string)
{
/*Ensure that input string isn't null and only do heavy lifting if it's not null*/
if (input_string)
{
char *stripped;
int i;
stripped = (char*)malloc(strlen(input_string)*sizeof(char) + 1);
for(i=0; i < strlen(input_string); i++)
stripped[i] = (isalpha(input_string[i]) ? toupper(input_string[i]) : input_string[i]);
return stripped;
}
/*default return val*/
return NULL;
}

Resources