Own version of strncpy shouldn't work, but it does - c

so here's the code.
#include <stdio.h>
#define MAXOUTPUT 10
void copy_n(char des[], char src[], int n);
int main(void)
{
int i;
char output[MAXOUTPUT];
copy_n(output, "SomeTestInputHere", 26);
printf("%s\n", output);
for(i=0;output[i]!='\0';i++)
printf("%c\n", output[i]);
return 0;
}
void copy_n(char des[], char src[], int n)
{
int i;
for(i=0;i<MAXOUTPUT;i++)
{
if(i<n)
des[i]=src[i];
else
des[i]='\0';
}
}
Why won't it crush when printing a string or char by char? Where does the terminating NUL come from here?
It's for Reek's Pointers on C, and is supposed to copy n characters, filling with NUL when, des>=src.But when src>des it should copy all chars without terminating NUL.

Your copy_n function for loop uses the constant MAXOUTPUT as the guard in the loop; and MAXOUTPUT has a value 10.

Related

Stack smashing detected in C - why does this happen?

I have the following function, which, given a string, should find the most recurrent couple of letters in it and store the result in a different string.
For example - for the string "ababa", the most recurrent couple would be "ba", and for "excxexd" it would be "ex". This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
void printError(){
printf("Error: please check your input\n");
}
bool isLexicographicallyPreceding(char couple1[], char couple2[])
{
if (strcmp(couple1, couple2)>=0) return true;
return false;
}
void coupleDetector(int length, char word[], char result[])
{
char couples[length-1][2];
for (int i=0; i<length-1; i++)
{
char couple[2] = {word[i], word[i+1]};
strcpy(couples[i], couple);
}
char element[]="";
int count=0;
for (int j=0; j<length-1; j++)
{
char tempElement[2];
strcpy(tempElement,couples[j]);
int tempCount=0;
for (int p=0; p<length-1; p++)
{
if (couples[p]==tempElement) tempCount++;
}
if (tempCount>count)
{
strcpy(element, tempElement);
count=tempCount;
}
if (tempCount==count)
{
if (isLexicographicallyPreceding(tempElement,element) == true) strcpy(element, tempElement);
}
}
strcpy(result,element);
}
int main() {
//Supposed to print "ba" but instead presents "stack smashing detected".
int length=5;
char arr[] = "ababa";
char mostCommonCouple[2];
coupleDetector(length,arr,mostCommonCouple);
printf("%s", mostCommonCouple);
return 0;
}
The code compiles without errors, but for some reason does not work as intended but prints out "stack smashing detected". Why would that be? Advices would be very helpful.
Thanks.
In trying out your program, I found a few of your character arrays undersized. Character arrays (strings) need to be sized large enough to also include the null terminator value in the array. So in many locations, having a two-character array size is not sufficient and was the cause of the stack smashing. With that in mind, following is a refactored version of your program.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
void printError()
{
printf("Error: please check your input\n");
}
bool isLexicographicallyPreceding(char couple1[], char couple2[])
{
if (strcmp(couple1, couple2)>=0) return true;
return false;
}
void coupleDetector(int length, char word[], char result[])
{
char couples[length-1][3];
for (int i=0; i<length-1; i++)
{
char couple[3] = {word[i], word[i+1], '\0'};
strcpy(couples[i], couple);
}
char element[3]; /* Define the character array */
strcpy(element, ""); /* Then initialize it if need be */
int count=0;
for (int j=0; j<length-1; j++)
{
char tempElement[3];
strcpy(tempElement,couples[j]);
int tempCount=0;
for (int p=0; p<length-1; p++)
{
if (couples[p]==tempElement) tempCount++;
}
if (tempCount>count)
{
strcpy(element, tempElement);
count=tempCount;
}
if (tempCount==count)
{
if (isLexicographicallyPreceding(tempElement,element)) strcpy(element, tempElement);
}
}
strcpy(result,element);
}
int main()
{
//Supposed to print "ba" but instead presents "stack smashing detected".
int length=5;
char arr[] = "ababa";
char mostCommonCouple[3]; /* Notice size requirement to also contain the '\0' terminator */
coupleDetector(length,arr,mostCommonCouple);
printf("%s\n", mostCommonCouple);
return 0;
}
Here are some key points.
Viewing the code, most sizes for arrays was enlarged by one to accommodate storage of the null terminator.
Work fields such as "element" need to be defined to their proper size so that subsequent usage won't also result in stack smashing.
Testing out the refactored code resulted in the following terminal output.
#Vera:~/C_Programs/Console/Recurrent/bin/Release$ ./Recurrent
ba
So to reiterate, be cognizant that character arrays normally need to be defined to be large enough to contain the largest expected string plus one for the null terminator.
Give that a try and see if it meets the spirit of your project.

Null pointer with unsigned char in c

I'm constructing an unsigned char * in c and I want to know how I finish it. So usually at the end of my memories I put '\0' but unsigned char recognize it as a 0.
so when I do something like that :
void complement(unsigned char *c, int n){
while(*c!='\0'){
printf("%d\n", n-(*c));
c++;
}
}
it stop when I read "0" (and when I read 0 I want to print n, the complement)
So what can I use to have a proper ending condition to my while ?
Perhaps you're allowed to switch from while to do-while like this?
#include <stdio.h>
void complement(unsigned char *c, int n)
{
do{
printf("%d\n", n-(*c));
printf("The character is %c\n", *c); // Just for debugging...
}while(*(c++)!='\0');
}
int main(){
unsigned char *toPrint = (unsigned char *)"Print me!\0";
complement(toPrint, 0);
return 0;
}

Printf writing extra character on occasion

this is the code, it is supposed to invert a string.
#include <stdio.h>
void StrRev(char str[]) {
int len=strlen(str);
char out[len];
int i;
for(i=0;i<len;i++){
out[i]=str[len-i-1];
}
printf("%s",out);
}
int main(void) {
StrRev("TestString");
return 0;
}
expected output:
gnirtStseT
actual output:
gnirtStseT#
the same thing happens with other inputs, while not on some others.
compiled with MingW on Code::Blocks
Two issues:
You fail to #include <string.h>, so there's no declaration for strlen. So the function is implicitly declared as int strlen(). So add that to the top of the file.
You also aren't adding the null terminating character to your reversed string.
After the for loop, set one additional character in the array to 0. Also, you'll need to make the array one larger to fit it.
#include <stdio.h>
// import declaration of strlen
#include <string.h>
void StrRev(char str[]) {
int len=strlen(str);
char out[len+1]; // increase length to make room for null terminator
int i;
for(i=0;i<len;i++){
out[i]=str[len-i-1];
}
out[i]=0; // add null terminator
printf("%s",out);
}
int main(void) {
StrRev("TestString");
return 0;
}
strlen() returns the length of the string without the null terminator at the end. So when you're copying over the characters, you're skipping the NULL at the end. If you simply use
int len=strlen(str) + 1;
instead of
int len=strlen(str);
Then everything should work.

Using string as parameter for function

I am trying to use a function with a string as a parameter. I am running into a couple of error messages. First, it says that string[i] is not an array, pointer, or vector, despite the fact that string is a character array. Secondly, it says that I am doing a pointer to integer conversion. Here is my code:
#include <stdio.h>
#include <string.h>
void example (char string) {
int i;
for (i = 0; i < strlen(string); i++) {
printf (string[i]);
}
}
int main (void) {
example("I like pie");
return 0;
}
void example(char string) should be void example(char *string). You declared it to take a character, you want it to take a character pointer or array.
Also, you need to tell printf you are giving it a character: printf("%c", string[i]);.
Your API is wrong it should be
void example (char *string) { // string is a pointer
int i;
size_t n = strlen(string);
for (i = 0; i < n; i++) {
printf ("%c",string[i]); // print character using %c
}
}
Calculate the string length before the loop , calling strlen() in each iteration is not a good idea.
PS: what string points to is read-only you can't modify it
You should use void example(char *string) instead of void example (char string).
#include <stdio.h>
#include <string.h>
void example (char *string) {
int i;
for (i = 0; i < strlen(string); i++) {
printf ("%c",string[i]);
}
printf("\n");
}
int main (void) {
example("I like pie");
return 0;
}
Your function example just receives a character. To get a string you can use a pointer. Also you can use "%s" format specifier in printf instead of using the for loop and strlen() function.
#include <stdio.h>
#include <string.h>
void example (char *string) {
int i;
printf ("%s\n",string);
}

Stray characters in char array

I am having a problem with this code, this code is a encryption for a rail cipher and if you enter in an input "testing" you should get an output "tietnsg" which i do get.
However if i change the input to "testingj" i get an output of "tietnjsgp?²!lj" i can see from my debugging the "?²!lj" appears to be tagged on during the last fill in the toCipher function
does anyone know how to fix it other than the way that i did it?
/*
CIS Computer Secutrity Program 1
10-10-14
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
char *toCipher(char **arr,int x,int y);
char *Encrypt(char *pT, int size);
char **create(int x,int y);
void FreeArr(char **array, int y);
void print(char *word,int strl);
int main(){
char pt[]= "testingj";
char *word = Encrypt(pt,3);
print(word, sizeof(pt));
free(word);
}
/*
Take in a pointer to a word, and the lenght of the string
Post print each char in the array, (used beacuase i had some issues with the memory, i keep getting extra adresses
*/
void print(char *word,int strl){
int i;
for(i=0;i<strl-1;i++){
printf("this is correct %c",word[i]);
}
printf("\n");
}
/*
Pre, take in the pointer to the plain text word to be encrypted as well as the depth of the Encryption desired
Post: Construct the array, insert values into the 2d array, convert the 2d array to a 1d array and return the 1d array
*/
char *Encrypt(char *word,int y){
int x = strlen(word);
int counter=0;
int ycomp=0;
int rate=1;
char **rail = create(x,y);
while(counter<x){
if(ycomp==y-1){
rate=-1;
}
if(ycomp==0){
rate=1;
}
rail[counter][ycomp]=word[counter];
ycomp=ycomp+rate;
counter++;
}//end of rail construction
char *DrWord = toCipher(rail,x,y);
FreeArr(rail,y);
return(DrWord);
}
/*
Create a dynamic 2d array of chars for the rail cypher to use
Take in the dimensions
return the pointer of the rails initial address, after it created the space for the rail
*/
char *toCipher(char **arr,int x,int y){
int xI =0;
int yI=0;
int counter =0;
char *word = (char*)malloc(x);
int i;
for(yI=0;yI<y;yI++){
for(xI=0;xI<x;xI++){
if(arr[xI][yI]!= 0){
word[counter]=arr[xI][yI];
counter++;
}
}
}
printf("this is the problem %s\n",word);
return(word);
}
char **create(int x, int y){
char **rail;
int i,j;
rail = malloc(sizeof(char**)*x);
for(i=0;i<x;i++){
rail[i]= (char*)malloc(y * sizeof(char*));
}
for(i=0;i<y;i++){
for(j=0;j<x;j++){
rail[j][i]= 0;
}
}
return(rail);
}
/*
Pre, take in a malloc'd array, with the height of the array
free the malloc calls one by one, and finally free the initial adress
*/
void FreeArr(char **array, int y){
int i;
for(i=0;i<y;i++){
free(array[i]);
}
free(array);
}
In toCipher, the word is printed without nul-termination. Either:
char *word = (char*)malloc(x+1); // allocate an extra char for nul.
word[x] = 0; // add the nul at the end.
or:
printf("this is the problem %.*s\n",x,word); // limit characters printed to x.
I forgot to initialize word to 0, the tagged memory if you watch it in debug mode was not being replaced, therefore was tagged along in the newly constructed string

Resources