I am sorry for the vague title, but I am having a very hard time figuring out how to describe this issue. I am trying to add data to an array and somehow it is all getting written to index 0 despite my explicitly indicating otherwise. I have created a minimal sample.
Expected Behavior
With command line arguments as -u rwx -g rw -o r:
bins[0] == "111"
bins[1] == "110"
bins[2] == "100"
Actual Behavior
Indices 0, 1 and 2 all end up as "100". If you put a printf() to check their value inside the various case statements, you will find that, for instance, when case 'g': runs, bins[1] == "110" AND bins[0] == "110". When case 'o': runs, all three indices will will hold the value "100".
Minimal functional sample
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void processPerms(char *targets, char **perms, char **bins, const size_t arrSize) {
for(int i = 0; i < arrSize; i++) {
//This string will be modified
//so that the right bits will
//be set.
char binDig[] = "000";
//We decide which, if any, bit
//to set based upon the current
//letter being considered.
for(int k = 0; k < strlen(perms[i]); k++) {
switch(perms[i][k]) {
case 'r':
binDig[0] = '1';
break;
case 'w':
binDig[1] = '1';
break;
case 'x':
binDig[2] = '1';
break;
}
}
//Here, we check the target
//whose index corresponds to
//the index of the permissions
//string we just accessed.
//They will always be in
//an order where the related
//target and perm str are in
//the same array position.
switch(targets[i]) {
case 'u':
bins[0] = binDig;
//bins[0] == "111"
break;
case 'g':
bins[1] = binDig;
//bins[0] == "110"
break;
case 'o':
bins[2] = binDig;
//bins[0] == "100" && bins[1] == "100"
break;
}
}
}
int main(int argc, char *argv[]) {
const size_t arrSize = (argc-1)/2;
char *targets = (char*)calloc(arrSize, sizeof(char));
char **perms = (char**)calloc(arrSize, sizeof(char*));
//Copying just the letters
//of the args into these
//arrays.
for(int i = 0; i < arrSize; i++) {
targets[i] = argv[i+(i+1)][1];
}
for(int i = 0; i < arrSize; i++) {
perms[i] = argv[i*2+2];
}
//This array should hold three
//strings which shall be binary
//representations of the
//permissions
char **bins = (char**)calloc(3, sizeof(char*));
processPerms(targets, perms, bins, arrSize);
return 0;
}
bins[2] = binDig;
This will make you point to a variable which has automatic storage duration. This is a gateway to undefined behavior when you are returning it from the function. The life time of the variable is over as in this case and accessing it is UB.(Dereferencing a pointer to variable beyond its lifetime is Undefine d behavior).
A easy solution would be to use (This is part of POSIX standard but it is common enough) (In case you don't have this, you can allocate memory and copy to it the content of the array binDig).
bins[2] = strdup(binDig);
(Make the same changes for bins[0] and bins[1]).
Making this change as mentioned gives the expected behavior of being bins[0] equal to "111" and so on. The only thing is that, you need to free the dynamically allocated memory (including as that of returned by strdup
when you are done working with it). Similarly, don't cast the return value of malloc,calloc etc(because void* to char* is an implicit conversion). And check the return value of malloc/calloc.
The lifetime of you binDig array is limited by one iteration of the outer for cycle. This binDig array gets destroyed at the end of each iteration and created anew at the beginning of the next iteration.
This means that everything you do during each iteration of the outer cycle is lost when that iteration ends. The value of bins[] that you assigned during that iteration begins to point to some indeterminate location in memory where nothing exists anymore. Any attempts to access data through the corresponding bins[] entries lead to undefined behavior.
In real life each iteration of the cycle will typically recreate binDig at exactly the same location in memory, which creates an illusion of all of your bins[] pointers remaining valid but pointing to the same value. But this is a mere illusion. The behavior is already undefined at that point.
When the outer cycle ends the binDig array disappears forever and all your bins[] pointers become hopelessly invalid for good. But that's just the last straw. Your program died well before that moment.
Related
I've been trying to handle multiple functions which the user can select from, but for some reason, unexpected input isn't causing the developed reaction, freezing instead.
int main(){
int done = 0, isModeValid = 1;
char nextMode[15], *options[] = {"quit", "test", "getASCII"};
while(done == 0){
cls();
isModeValid = 0;
text(1);
currentOptions(options);
gets(nextMode);
int i = 0;
for(i = 0; i < (sizeof(options)); i++){
if(strcmp(nextMode, options[i]) == 0){
done = runMode(i);
break;
}
//Error seems to happen after this point
if(strcmp(nextMode, options[i]) != 0 && i == sizeof(options)){
cls();
text(3);
Sleep(750);
}
}
}
return 0;
}
void cls(){
system("cls");
}
You are invoking undefined behaviour. sizeof yields the size of the argument in bytes/chars, not the length of the array. So you are iterating over more elements than the array actually contains and try to access elements past its bounds.
Use sizeof(options) / sizeof(options[0]) to get the length independent from the type of each entry.
Note: Declaring the array static would make its allocation and initialization before main is called. Your current version will do that each time the function is called. While uncritical for main, it will be significant for other functions which are called more than once.
To get the number strings in options, you need (sizeof(options)/sizeof(options[0])), not just sizeof(options)... so your for loop is looping too many times, and you're accessing out of bounds.
Also, your second if never executes because i will never get to sizeof(options).
I tried creating an array of ten random strings that would print directions randomly. Such as first time "up down right ... rot_x" and second time "forward rot_y up ... down" etc. I tried using a char* pc and allocating memory for it with memset but that didn't work so I tried the following code but I'm getting weird output. How can I fix this?
int main()
{
int r_num;
char r_arr[10][10];
for (int i = 0; i < 10; i++)
{
r_num = rand() % 10;
switch(r_num)
{
case 0: strcpy(r_arr[0], "up");
break;
case 1: strcpy(r_arr[1], "down");
break;
case 2: strcpy(r_arr[2], "left");
break;
case 3: strcpy(r_arr[3], "right");
break;
case 4: strcpy(r_arr[4], "rot_x");
break;
case 5: strcpy(r_arr[5], "rot_y");
break;
case 6: strcpy(r_arr[6], "rot_z");
break;
case 7: strcpy(r_arr[7], "forward");
break;
case 8: strcpy(r_arr[8], "back");
break;
case 9: strcpy(r_arr[9], "reset");
break;
default:
fprintf(stderr, "Cannot process input/n");
}
}
for (int i = 0; i < 10; i++)
{
printf("%s ", r_arr[i]);
}
return 0;
}
here's my output:
up ?V? left right rot_x ?V? forward back reset
A few problems with your code are:
You aren't seeding rand(), so every run of your program will generate identical output. You need to use srand() first with a seed. Traditionally one uses time().
Secondly despite the randomness you are unrandomly (is that a word?) filling r_arr. "up" will always be first, "down" will always be second etc.... Instead you should do something like
for (int = 0; i< 10; i++) {
r_num = rand() % 10;
strcpy(r_arr[i], getDirection(r_num));
}
where getDirection() will return a string based on an integer input (e.g.: via a case statement that associates 0 with "up").
Your r_arr needs to be initialized. There is no guarantee in your current code that each entry in the array will be populated with chars before being accessed. If you implement suggestion 2 then you wont have a problem. Today however your code is accessing potentially uninitialized memory.
As noted by others above, your issue is that you're not indexing your array with the iteration number of your loop. You had:
case 0: strcpy(r_arr[0], "up");
Whereas you should have had:
case 0: strcpy(r_arr[i], "up");
The additional thing that I wanted to point out is that rand() uses a linear equation (at least on many systems) so it will be impossible for you to ever get two even numbers in a row or two odd numbers in a row, which is not very random. Hence I suggest something like:
r_num = (rand() >> 8) % 10;
As the commenters pointed out, you are randomizing not what value you put in each position but which positions get filled with their preset value. Also, your use of a switch statement here is just odd. Try something like:
char value_arr[10][10]={"up", "down", "left", "right", "rot_x", "rot_y", "rot_z", "forward", "back", "reset"}
for (int i = 0; i < 10; i++)
{
r_num = rand() % 10;
strcpy(r_arr[i], value_arr[r_num]);
}
Print the strings inside the switch instead of the for-loop at the end.
Maybe you'll also need something like:
srand (time(NULL));
here is a code that fits exactly to your need :
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// we use this instruction to get a random result each time we run the program
srand(time(NULL));
int r_num;
char r_arr[10][10];
// the dictionary array will be used to take from it the possible strings
char dictionary[10][10]={"up","down","left","right","rot_x","rot_x","rot_x","forward","back","reset"};
int i=0;
for(i=0; i<10; i++)
{
// r_num will be assigned randomly an index from dictionary tab
// the general equation is (rand()%(max-min+1))+min to get a random value
// between max and min inclusive
r_num=(rand()%(9-0+1))+0;
// we will put the random string chosen in the array r_num each time
strcpy(r_arr[i],dictionary[r_num]);
}
// this loop will print the result
for(i=0; i<10; i++)
{
printf("r_arr[%d]=%s \n",i,r_arr[i]);
}
return 0;
}
by looking at your output i noticed some strange values like ?v?,
the problem is that not all numbers between 0 and 9 will be generated by
the rand() function which mean that the corresponding array element(to those numbers) will not be initialized and therefor it contain garbage values from what ever was stored in that memory address.
i hope that explain why you are getting those strange values.
I'm learning C from a book C programming:Modern approach. Right now I'm going trough exercises about arrays. One of the exercises is to write a filter that prints the input message differently.
I've gotten so far (see the code below), everything works fine, until the character count exceeds 44, then it prints random symbols. If the character count is below 44 everything works fine. I have absolutely no clue why it does that. Where is the problem and what might be the solution?
int i = 0, k = 0;
char message[k],ch;
printf("Enter a message: ");
while(toupper(ch = getchar()) != '\n')
{
message[k] = ch;
k++;
}
printf("In B1FF-speak: ");
for (i = 0; i <= k - 1; i++)
{
switch(toupper(message[i]))
{
case 'A':
printf("4");
break;
case 'B':
printf("8");
break;
case 'E':
printf("3");
break;
case 'I':
printf("1");
break;
case 'O':
printf("0");
break;
case 'S':
printf("5");
break;
default:
printf("%c", toupper(message[i]));
break;
}
}
int i = 0, k = 0;
char message[k],ch;
You've defined message as a variable length array (VLA). (This is a feature that doesn't exist in the 1990 version of C; it was added by the 1999 standard and made optional by the 2011 standard.)
Since the value of k is 0, the length of message is 0. C does not support zero-length arrays. Defining an array with a constant length of zero is illegal (a constraint violation, requiring a diagnostic). Defining a variable length array with a length of zero has undefined behavior.
The length of a VLA is fixed when it's defined. Changing the value of k later on does not change the length of the array. Your code seems to assume that it will.
Your program seems to work for lengths up to 44. That's the nature of undefined behavior. The worst thing that can happen is that your program seems to work "correctly"; that just means that you have a bug that's difficult to detect.
If you want to store arbitrarily many elements in an array, you can either define it with a size that's big enough in the first place (it can be difficult or impossible to determine how big it has to be), or you can use realloc() to allocate the array dynamically and expand it as needed. (realloc() doesn't actually expand the array; it creates a new array with a larger size and copies the contents of the old array into the new array. And it can fail if there isn't enough available memory; always check the value it returns to determine whether it succeeded or failed.)
I am trying to write a program which calculates and prints the GC content of a string of DNA(which is input through a txt file). That is, the percentage of G's and C's in a string of DNA. Here is my function for the GC percentage:
void updateGCCount(char s[], int *gc, int *at) {
char c[MAXLENGTH];
int i,GCcount,ATcount;
float len,GCpercentage;
GCcount=0;
ATcount=0;
for(i=0;c[i]!='\0';++i)
{
if(c[i]=='G' || c[i]=='C')
{
++GCcount;
*gc=GCcount;
}
if(c[i]=='A' || c[i]=='T')
{
++ATcount;
*at=ATcount;
}
}
strcpy(c,s);
len=strlen(c);
GCpercentage=*gc/len;
printf("GC-content: %.2f\n",GCpercentage);
}
This is my function definition, and the part which is supposed to correctly print the GC percentage is what I am not sure about. Below is my main program which utilizes the input text file.
#include "genomics.h"
int main(){
char s[MAXLENGTH];
int gc, at;
scanf("%s",s);
printf("Sequence : %s\n",s);
updateGCCount(s, &gc, &at);
return 0;
}
Any help or advice on why I am not getting a correct value for the GCpercentage would be great. Thank you in advance
You're doing your tests on char array "c":
char c[MAXLENGTH];
...
for(i=0;c[i]!='\0';++i)
{
if(c[i]=='G' || c[i]=='C')
{
++GCcount;
*gc=GCcount;
}
if(c[i]=='A' || c[i]=='T')
{
++ATcount;
*at=ATcount;
}
}
If should be on s, the array that you passed in. The c array is probably superflous, you should be able to get the length from s as well
c is not initialize, so *gc and *at are not updated at all and they contain garbage..
here you should use s instead of c
for(i=0;c[i]!='\0';++i)
{
if(c[i]=='G' || c[i]=='C')
{
++GCcount;
*gc=GCcount;
}
if(c[i]=='A' || c[i]=='T')
{
++ATcount;
*at=ATcount;
}
}
That's a strongly un-idiomatic program. Consider the following.
#include <stdio.h>
#include <stdlib.h> /* for exit(3) */
float count_gc(const char* s)
{
You have no need to pass information back via variables passed in by reference. Functions return values -- typically 'the answer'.
You're simply scanning the content of the argument string s, so there's no need to copy it anywhere.
As others have pointed out, you were scanning the contents of the array c[] before you copied anything in to it -- you were counting 'G' and 'C' in a (probably large) random block of memory. Keeping things simple avoids mistakes like that.
int nvalid = 0;
int gccount = 0;
float result;
for (; *s != '\0'; s++) {
Although the for loop you wrote isn't wrong, it's somewhat un-idiomatic. Here, we examine the character pointed to by the pointer s, and then increment the pointer, until we find ourselves pointing at the \0 that terminates the string. Yes, this means we 'lose' the initial value of the argument, but we don't need it after the loop, so that doesn't matter.
switch (*s) {
A switch is a more natural construction here. You're looking for a small set of possible values that *s (that is, the character the pointer is currently pointing at) may have.
case 'G':
case 'C':
nvalid++;
gccount++;
break;
case 'A':
case 'T':
nvalid++;
break;
default:
/* unexpected character -- ignore it */
break;
Every switch statement should have a default clause -- one should always think of what's supposed to happen if none of the case clauses match. In this case, we just ignore this character.
}
}
if (nvalid == 0) {
fprintf(stderr, "No valid letters found!\n");
result = 0.0;
} else {
/* Multiply by 1.0 to convert integer gccount to a float */
result = 1.0*gccount / nvalid;
}
return result;
We return the result to the caller rather than printing it out inside the function. Functions shouldn't 'chatter', but leave all of the I/O in one place, typically leaving the main function (or something higher up) to look after that.
}
int main(int argc, char** argv)
{
if (argc != 2) {
/* Give the user a hint on how to call the program */
fprintf(stderr, "Usage: gcat <string>\n");
exit(1);
}
printf("Sequence GC-content = %g\n", count_gc(argv[1]));
}
I run that with:
% cc -o gcat gcat.c
% ./gcat "GCAT ATx foo"
Sequence GC-content = 0.333333
%
With C, it's very easy to tie yourself in knots, very quickly. Aim for simplicity always.
I am trying to iterate through an array that will contain up to a maximum of 4 elements - no other knowledge of the array-length exists.
Pseudo Code
void insert_vals(uint8_t num, uint8_t *match_num, uint8_t *value)
{
uint8_t i;
while(data_exists) // how do I determine if data exists in 'value'?
{
switch(num)
{
case 0:
{
switch(match_num[i])
{
case 0:
hw0reg0 = value[i];
case 1:
hw0reg1 = value[i];
case 2:
hw0reg2 = value[i];
case 3:
hw0reg3 = value[i];
}
}
case 1:
{
switch(match_num[i])
{
case 0:
hw1reg0 = value[i];
case 1:
hw1reg1 = value[i];
case 2:
hw1reg2 = value[i];
case 3:
hw1reg3 = value[i];
}
}
// etc. 2 other cases
}
i++;
}
}
Calling Example (Pseudo Code)
/*
* num: hardware device select from 1 - 4
* match_num: 4 possible matches for each hardware device
* value: 32-bit values to be assigned to 4 possible matches
* NOTE: This function assumes hardware devices are selected
* in a consecutive order; I will change this later.
*/
// example calling code - we could have configured 4 hardware devices
insert_vals(0, [0, 1], [0x00000001, 0x000000FF]); // arg2 and arg3 equal in length
How can I accomplish this?
In a character array, C will automatically add '\0' to the end of the array, but this does not seem to be the case for an integer array. If I was somehow able to determine the length of match_num and value (see if statement) at runtime originally, then that would allow me to create a for loop.
Edit
Since I know that there will be a maximum of 4 elements, couldn't I do something similar to the following?
void insert_vals(uint8_t num, uint8_t *match_num, uint32_t *value)
{
int i;
for(i = 0; i < 4; i++)
{
if(value[i] == -1)
break;
else
{
// Assign data
}
}
}
You can't get the length of an array pointed to given only the pointer. Either you have to pass the length, or it must be constant (always 4) with some sentinel value in the unused elements -- a value that is somehow invalid for your computations (like NUL is for strings).
Is there a value you can guarantee it's not in the "usable" data? (e.g. 0 is no valid character for character strings, therefore Mr. Kernighan and Mr. Ritchie decided to pick it as a "end of array" marker. You could do the same with any value.
Say you know your integer values are between 0 to 512, so you could initialize the whole array e.g. to 1024, then fill it and iterate through it until a number >512 occurs (which has to be your end of array marker).
Another possibility is to pass the number of elements in the array along with the array.